Driving an LVDS LCD - Page 1
Forum section: electronics / general

author: Miti
author_rank: Super Contributor
timestamp: April 02, 2021, 01:49:47 am
content: I'm trying to make this LCD module do something and the datasheet is a bit confusing ... to me.First time I look at LVDS LCD and I don't understand how the sync works and why the pixel clock is shifted relative to the LVDS data. Is there any documentation I can read? Is there a verilog code example I can play with?Miti

author: asmi
author_rank: Super Contributor
timestamp: April 02, 2021, 02:14:31 am
content: What FPGA are you using? For Xilinx 7 series check out xapp585 application note.

author: Miti
author_rank: Super Contributor
timestamp: April 02, 2021, 02:19:21 am
content: I have two dev boards with Altera Cyclone II and Cyclone IV.

author: asmi
author_rank: Super Contributor
timestamp: April 02, 2021, 02:38:17 am
content: Quote from: Miti on April 02, 2021, 02:19:21 amThen maybe some of our resident Altera lovers would pitch in on specifics of IO part.But basically the "clock" is not really a clock, as it's used for framing (so that receiver can find boundaries of a single transmission). If you look closely, not only it's shifted, but it's also non-symmetrical length-wise (it's high for 4 bit periods, but low for only 3), so that if you sample that clock every bit period, you will get a sequence 1100011. So when receiver tries to lock onto the data stream, it basically bitslips the reception by 1 bit time until it can see that sequence on a clock line - and that's how it knows that it's now properly aligned to the boundaries and so it can start processing data from the data lines knowing they are framed properly. Check the diagram in attachment - I think it shows it more clearly.The easiest way to implement it is by using 7:1 SERDES modules - one for a "clock" line (which transmits a fixed pattern of 1100011 or 1100001 depending on a panel), and then one more SERDES module for each of data lines. I don't know if Altera supports such mode, so this part you will have to find out yourself, or wait to see if anyone familiar with Altera devices would pitch in.Also you might want to brush up on your Google-fu. This standard is quite popular even nowadays, so I'm fairly certain you will be able to find some info on this subject on the Internet.

author: BrianHG
author_rank: Super Contributor
timestamp: April 02, 2021, 03:15:50 am
content: Quote from: Miti on April 02, 2021, 01:49:47 amI do not like that datasheet's illustration. So, take a look at page 13 at the bottom. See that they 'Recommended transmitter: DS90C383 (Texas Instruments) or equivalent'. I would first go to TI's DS90C383 data sheet and see how they output their data.For Altera, you will end up using the 'altlvds_tx' function set the 4 channels and the appropriate number of bits/channel.TI illustrations are dead simple and properly explained. You would have to set the altlvds_tx to 7 bits. The CLK out channel will be a fixed 7'b1100011' number while you video and embedded sync will be on the other 3 channels. (Note that channel TD isn't used as your chosen panel is only 18bit color.)Modelsim will have no trouble showing you what your code is outputting when testing.When assigning the output pins, you will need to set them to LVDS (higher speed, but fewer choice of IOs on FPGA), or, LVDS_E_3R (more flexible choice of almost all IOs on FPGA) outputs.(holy shit, they scrambled up the bit positions....)Or, if you can find a dev board with a similar LCD already on it, download their example CD and use their code.

author: Miti
author_rank: Super Contributor
timestamp: April 02, 2021, 12:53:14 pm
content: Quote from: asmi on April 02, 2021, 02:38:17 amTo be honest, I had a free Altera dev board at work and that's the reason why I started with Altera, I don't have preferences, at my level they all do the job. Moreover, I installed two versions of Quartus, one for Cyclone II and one for Cyclone IV without any issue. Couple of months ago I tried to install Xilinx ISE 14.7 Win7 in my laptop and, after install, it would't start no matter what. I tried multi file and single file installer with no luck.Quote from: asmi on April 02, 2021, 02:38:17 amNow that's good info, thanks! I got confused because it is shown as pixel clock in some datasheets. I saw that it is asymmetrical and my thought that it is used for strobe, in a weird way that I couldn't understand.

author: Miti
author_rank: Super Contributor
timestamp: April 02, 2021, 01:20:45 pm
content: Quote from: BrianHG on April 02, 2021, 03:15:50 amYes, me neither and I saw that datasheet. What's missing in the LCD datasheet, compared to Ti datasheet, are the HSync and VSync, they show two dashes instead. Does it mean they use DE for sync or how does the receiver know which is pixel 0,0?Quote from: BrianHG on April 02, 2021, 03:15:50 amYeap, I did look at that megafunction and this info clears up some question marks. I may have some more questions later on.Quote from: BrianHG on April 02, 2021, 03:15:50 amI have yet to learn how to ModelsimQuote from: BrianHG on April 02, 2021, 03:15:50 amI searched hard on Terasic's site and couldn't find one. I'll try again later, after I change the tires.

author: SiliconWizard
author_rank: Super Contributor
timestamp: April 02, 2021, 02:32:50 pm
content: It's standard LVDS interface for LCDs. Yeah, I know it looks a bit confusing when you're first exposed to it. But it's standard really.You need a 7:1 serializer, and the "clock" signal needs to be generated in the same way data is - through a serializer! The LCD controller will reconstruct the pixel clock from the CLK signal, which serves both as a frame sync for pixel data and as a reference clock for reconstructing the pixel clock.asmi pointed you to an app note that should help you understand.For Lattice devices, there's even an IP available for LVDS 7:1. You can check out the document " MachXO2, MachXO3 and ECP5 7:1 LVDS Video Interface".

author: langwadt
author_rank: Super Contributor
timestamp: April 02, 2021, 03:06:03 pm
content: Quote from: SiliconWizard on April 02, 2021, 02:32:50 pmand with ~32MHz * 7 = ~225Mbit rate it might just be slow enough that using the serializer isn't required

author: asmi
author_rank: Super Contributor
timestamp: April 02, 2021, 03:42:02 pm
content: Quote from: Miti on April 02, 2021, 12:53:14 pmISE is not updated for many years now and is only required if you want to use older devices (before 7 series). For 7 series and above you can/need to use Vivado/Vitis.

author: SiliconWizard
author_rank: Super Contributor
timestamp: April 02, 2021, 04:16:37 pm
content: Quote from: Miti on April 02, 2021, 12:53:14 pmI have been using ISE 14.7 on Win 7 without any problem for years. Still using it for supporting Spartan-6 designs.Since the supported devices are still sold by Xilinx, ISE is definitely still "supported". It just won't get any update. You might want to try contacting Xilinx for help.Note that I've never installed ISE on a 32-bit Windows, so if your Win 7 is 32-bit, I have no experience with that. But on Win 7/64 - no issues.

author: SiliconWizard
author_rank: Super Contributor
timestamp: April 02, 2021, 04:42:39 pm
content: Quote from: langwadt on April 02, 2021, 03:06:03 pmTo serialize data, you need a serializer.What you mean is that you don't necessarily need dedicated SERDES blocks for this, so the serializer can be implemented in HDL and use common FPGA logic.Note that 225Mbits/s is not very fast, but may still require defining proper timing constraints for IOs, and/or directly instantiate IOBs for reliable operation. The period is a mere 4.4ns...

author: langwadt
author_rank: Super Contributor
timestamp: April 02, 2021, 05:48:14 pm
content: Quote from: SiliconWizard on April 02, 2021, 04:42:39 pmyes, "the serializer" as in the SERDES blockusing IOB FFs should keep everything aligned

author: rstofer
author_rank: Super Contributor
timestamp: April 02, 2021, 06:45:27 pm
content: Quote from: Miti on April 02, 2021, 01:20:45 pmVHDLwhiz.com does a LOT of tutorials around Modelsim. As you might expect, it has a VHDL slant but the information is still valid.

author: BrianHG
author_rank: Super Contributor
timestamp: April 03, 2021, 12:05:34 am
content: Quote from: Miti on April 02, 2021, 01:20:45 pmIt is it's own compiler. Unlike Quartus, it will only output a logic analyzer waveforms. It compiles code in a second. And your 'test-bench' file in Verilog or SystemVerilog is the top hierarchy which is nothing more than another verilog program to drive your design's inputs.You also can freeze you simulation and inspect any of your logic/variables anywhere in your code as well as add those regs to your simulation waveform.Yes, Quartus can setup and run Modelsim from your Quartus project, but to get those sweet 1 second re-compile and simulate, you should learn how to run Modelsim all on it's own. Then transfer your design .v to Quartus.Here is a step above beginner project I wrote which exclusively runs all in ModelSim or ActiveHDL, or with a patch from asmi, also runs in Vivado Simulator:https://www.eevblog.com/forum/fpga/systemverilog-example-testbench-which-saves-a-bmp-picture-and-executes-a-script/msg3436876/#msg3436876The .do script files will show you, (equivilant to a .bat for dos files) how I setup ModelSim and what it will run.All instructions are there as it is one of my tutorial projects, though, it is written in SystemVerilog, not Verilog. The 2 are close enough for you to understand.

author: Miti
author_rank: Super Contributor
timestamp: April 03, 2021, 09:49:33 pm
content: Quote from: SiliconWizard on April 02, 2021, 02:32:50 pmThat part I understand. The data is reconstructed, but how does it know which one is pixel 0,0? If you look at the datasheet that I attached here, there's a DE, a VS and a HS. My LCD does not seem to need HS and VS. I can only assume that DE timing is used for synchronisation. Long low level resets both, the horizontal and the vertical counter, and a short low level resets only the horizontal counter.

author: Miti
author_rank: Super Contributor
timestamp: April 03, 2021, 10:06:50 pm
content: Quote from: asmi on April 02, 2021, 03:42:02 pmQuote from: SiliconWizard on April 02, 2021, 04:16:37 pmI just wanted to get the feeling of it and, after looking at some dev boards on Ali, series 7 is more expensive than series 6. For learning, Spartan 6 would do it.I tried to install it on my work laptop and some people recommend disabling the security software but I can't do that on this laptop. I will try on my home PC one day.

author: DC1MC
author_rank: Super Contributor
timestamp: April 04, 2021, 08:39:11 am
content: Quote from: Miti on April 03, 2021, 10:06:50 pmIt only needs administrative privileges for the JTAG adapter device drivers, just for installation you could convince it to lay its eggsin a directory where you have access rights. As long as you're in the learning phase and don't talk with the hw, there is no need of JTAG adapter.Cheers,DC1MC

author: Scrts
author_rank: Frequent Contributor
timestamp: April 09, 2021, 04:26:46 pm
content: Quote from: Miti on April 02, 2021, 01:49:47 amI think this is the OpenLDI data format? I remember I had to do something like this a number of years ago and my solution was a simple 7 state machine running at pixel clock outputting the new "data clock", pixel and sync data. Worked well with 800x480 display.

author: SiliconWizard
author_rank: Super Contributor
timestamp: April 09, 2021, 06:21:51 pm
content: Quote from: Miti on April 03, 2021, 09:49:33 pmYep. I have used another LVDS LCD and that was the same. A DE signal serving as both Hsync and Vsync. See pp. 17 to 19.Then the DE signal is transmitted on the D2+/- pair, along with B2-B5. See p. 15.

author: Miti
author_rank: Super Contributor
timestamp: April 10, 2021, 12:23:21 am
content: Quote from: DC1MC on April 04, 2021, 08:39:11 amI'm not sure if that is my issue. I have admin privileges, I tried to run the install as admin, there's no complain during the install but it simply doesn't start.

author: Miti
author_rank: Super Contributor
timestamp: April 10, 2021, 09:11:08 pm
content: Ok, so here's my ALTLVDS_TX module and I think I got it right because I see exactly what I expect at the outputs. Now I would need a video controller and a pattern generator. I think I would need the tx_outclock for that, I was thinking that the falling edge would increment the H and V counters, and the rising edge would load the tx_in register. However, if you look at the phase of that clock relative to the first bit on one LVDS output, the rising edge comes after the data needs to be valid. What's the technique here? The phase shift of the tx_outclock relative to tx_out doesn't do it, I can't do negative phase shift.

author: BrianHG
author_rank: Super Contributor
timestamp: April 10, 2021, 10:12:33 pm
content: Quote from: Miti on April 10, 2021, 09:11:08 pmI'm having a little difficulty following your logic, or train of thought.Internally in the FPGA, everything should be at 1x clock, IE, 1 pixel clock, always rising edge, all video generator counter and image processors working at that 1x clock.You should be outputting the 18bit color data, 3 bit HS,VS,DE, (we are at 21 bits), plus the 7 bit clock pattern (we are at 28 bits) into the altlvds_tx singular 28bit parallel input. The altlvds_tx should take that data with pixel clock, in internally generate it's own PLL accelerating the 28bit parallel pixel clock speed input to a serial output stream of 4 lanes by 7x clock speed serial output.You should never have to worry about the when to increments the HS/VS on weird clock phases.Note that the altlvds can be setup to be clocked on the incoming data with the tx_inclock so you may ignore or disable the tx_outclock. The tx_outclock is at the same speed as the tx_inclock, just taken after the PLL generated by the altlvds_tx. If your design is very high FMAX and you need to run a serializer with a >250MHZ parallelinputwith GHz outputs, using this output as your logic design's system clock,not an output pin, helps improve fabric routing and FMAX limitations. You are running your parallel input at ~50MHz, so you don't need to use it.Do not look at the phase difference on the scope. The tx_outclock was not meant to be outputted, it is used to internally clock the logic input and it will appear as a weird phase compared to the output data as you are looking at the clock for the input gates, not the time from when that clock runs until the serial shift register output the data.Now, if you have having a pin-pin timing skew on the 4 bit output pins, this is a different problem where there are a few solutions to fix.Also, remember that the altlvds_tx will shift out the 7 bits from right to left...

author: Miti
author_rank: Super Contributor
timestamp: April 10, 2021, 11:01:31 pm
content: Quote from: BrianHG on April 10, 2021, 10:12:33 pmOk, my thought was that I need to register the tx_in inputs but what I take from your reply is that altlvds is internally registered and a change in the data input in the middle of a frame, does not affect the data output.Quote from: BrianHG on April 10, 2021, 10:12:33 pmDoes it? I set my D2 to "1011000", see the scope shot below. What am I missing?

author: BrianHG
author_rank: Super Contributor
timestamp: April 10, 2021, 11:24:59 pm
content: Quote from: Miti on April 10, 2021, 11:01:31 pmSorry, my mild form of dyslexia kicked in again...

author: BrianHG
author_rank: Super Contributor
timestamp: April 10, 2021, 11:27:43 pm
content: Quote from: Miti on April 10, 2021, 11:01:31 pmCorrect. In the FPGA, everything is expected to be valid by the next rising clock. The serial output is skewed/delayed due to internal logic and it is partially grater than a frame/clk_in.

author: Miti
author_rank: Super Contributor
timestamp: April 11, 2021, 01:50:40 am
content: So I'll have to use the second PLL to generate the pixel clock. For now I can use the 50MHz that's installed on the dev board, but for an exact 60Hz frame rate, I will need 32.256MHz. There's no oscillator with that frequency at Digikey, or anywhere. The only option that I found to generate the correct frequency is 45.1584MHz.Do you have any other suggestion?

author: BrianHG
author_rank: Super Contributor
timestamp: April 11, 2021, 03:41:04 am
content: Why not use 27MHz or 54MHz clock?Total width = 900, 800 pixels + 100 for sync, front and back porch. (32/48 pixels for Hsync should be good)Total height = 500, 480 lines plus 20 lines for sync, front and back porch. (3/6 lines for Vsync should be good)This gives a dead perfect 60Hz. Note that the 27/54MHz is good for synchronized 48KHz audio as it is used in MPEG2 video. Also note thatbroadcastvideo is not 60FPS, is it actually exactly 59.95FPS here in North America.Also, altpll can make a perfect 27MHz from a 50MHz or 48MHz source crystal.Unless your panel says it must have something like 1024 pixels per line exact always, there shouldn't be a problem with 900 pixels per line.Ok, if you must have 32.256MHz, buy a 25.088MHz (or multiple/divider there of) oscillator and setup the altpll to multiply by 9 and divide by 7. But, just try to find stock compared to 27MHz or 54MHz, or 50MHz if you want to use 2 PLLs to first generate the 27MHz from the 50MHz. Note that with some effort, you can setup the altlvds_tx by using 1 PLL to generate the 27MHz and 189MHz serial clock simultaneously yourself, then feed the 2 clocks to the altlvds_tx module.

author: BrianHG
author_rank: Super Contributor
timestamp: April 11, 2021, 04:19:27 am
content: 30MHz gets you really close to the LCD specs with 60HZ exactly if the LCD will take a video frame of 1000x500.This is close to 1024x525.Generally, many LCDs like the horizontal to be an even number while the vertical has some greater flexibility.

author: BrianHG
author_rank: Super Contributor
timestamp: April 11, 2021, 11:02:22 am
content: Just so you know, 4.032 crystals are dirt cheap at 45cents with stock at digikey. Teamed up with a cheap 1$ PLL clock generator IC, you can multiply that by 8 and get the exact 32.256 MHz.In fact, if you already need an external MCU like a PIC and it has a built in PLL where you can output 2x/4x/8x, such a crystal on the MCU with it's OSC output feeding the FPGA clk input, so long as it is above 5MHZ, you just need to do a multiply by x and you will get your 32.256 MHz exact.(Yes, as far as I know, a stupid PIC with an internal 8xPLL costs less than an IC with a XTAL input to generate a CLK output other than making your own XTAL oscillator with the FPGA combined with an inductor & 3 IOs to double that 4.032MHz to pass the required minimum 5MHz of the FPGA's PLL. You can play/test this immediately with a 4MHz crystal if you have one on hand. I would still recommend using a 74HC86 xor or 74HC4046 to double and buffer the crystal before the FPGA, but, these functions can be emulated on IOs of the FPGA.)Example, this PIC@1.08$:https://www.digikey.com/en/products/detail/microchip-technology/PIC32MM0016GPL020T-I-SS/6055556You last cheapest option is this IC@69cents:https://www.digikey.com/en/products/detail/microchip-technology/PL611-01-N12MC-R/7898437Sadly, your crystal range is between 10 and 30MHz, but, you can setup weird long multiplies/divides.

author: BrianHG
author_rank: Super Contributor
timestamp: April 11, 2021, 11:48:22 am
content: Why haven't you tried 18.432MHz?Digikey has plenty oscillators in stock thereby multiple manufacturersand packages all below $1.50. (Still, a minuscule fraction compared to 30MHz or 27MHz and 30MHz is cross compatible with my DDR3 ram controller's 300MHz clock using Cyc-IV/V/Max10. Also, testing with a 50MHz, you can make 30MHz easy.).18.432MHz X 7 / 4 = 32.256MHz.https://www.digikey.com/en/products/detail/kyocera-international-inc-electronic-components/KC2016Z18-4320C15XXK/11610008

author: Miti
author_rank: Super Contributor
timestamp: April 11, 2021, 04:45:43 pm
content: Quote from: BrianHG on April 11, 2021, 11:48:22 amYes, 18.432MHz is a good catch, thanks! I will do my experiments with the 50MHz that is already on board, fed to the second PLL. 50 X 5 / 7 is 35.714MHz, still below the maximum 36MHz. I don't have a real application now, it's just learning.

author: Miti
author_rank: Super Contributor
timestamp: April 11, 2021, 09:15:35 pm
content: I see colors... Some issues with my counters logic but in general it works.Edit: The entire image is shifted one pixel to the right. I assume it is related to the registering of the ALTLVDS data input.

author: SiliconWizard
author_rank: Super Contributor
timestamp: April 12, 2021, 12:28:51 am
content: Of course I haven't seen your code, but any registering shouldn't matter here. Just make sure the sync signal (DE) is properly generated. Adjusting the pixel shift should be fairly easy if you have made the front and back porch easy to modify.

author: BrianHG
author_rank: Super Contributor
timestamp: April 12, 2021, 01:00:14 am
content: Quote from: Miti on April 11, 2021, 09:15:35 pmNot possible. The 'DE' is sent with the valid pixel in parallel.Remember, if you are generating the output color based on the 'DE' or counters which count triggered from the DE, that data may be delayed by a clock compared to the 'DE'.Are you using the 1024 clocks per line, 525 lines, or a custom frame size?

author: Miti
author_rank: Super Contributor
timestamp: April 12, 2021, 01:46:41 am
content: Quote from: SiliconWizard on April 12, 2021, 12:28:51 amYes, I figured out that DE was coming when H_Count was at 1, not at 0 and I corrected it, but then the pattern was shifted 2 pixels to the right, which makes sense, it means that data is shifted 2 clocks relative to DE.My mistake is that I thought I can get away with no back porch, so start displaying from H_Count = 0 up to 799, then pull DE low, but that makes it harder to shift data. I'll have to start the active portion somewhere in the middle, say H_Count = 10 to 899, so I can shift the data few pixels to the left.Quote from: BrianHG on April 12, 2021, 01:00:14 amBoth, the H_Counter and DE are generated in one always @ block. The problem is that the X and Y coordinates that I pass to the pattern generators must be delayed, that's why I see the data for pixel 0 displayed on pixel 2.Yes, I'm using 1024 X 525 frame. As I said, I think I know what I need to do. Move the horizontal active area a bit to the right inside the H_Counter, and shift the X coordinates 2 pixels to the left. I think vertically I can start the active area from 0.

author: BrianHG
author_rank: Super Contributor
timestamp: April 12, 2021, 02:24:34 am
content: Remember, if the panel doesn't need the HS & VS, just the DE, it has no clue about your internal sync counter and all the relative positions & timing.All it cares is that the DE is high for 800 pixels per line.You place the picture inside there.Beginning your frame with your counters at 0x0 to 799x479 is perfectly fine. (Yes, remember the ending odd numbers, You do not know how many time I has to establish this with Nockieboy in the 8-bit GPU thread...)Having the counters wrap around at 1023 and 524 is fine and if you want syncs, just place them after the active picture area.Remember, if you construct the picture data output from the coordinates of those counters and that picture data takes 1 clock to compute, you need the DE to also take 1 clock to compute. If the picture takes 2 clocks, then the DE also should take 2 clocks.IE (additional clock) ->DE_generated_from_screen_coords <= (x_coord < 800) && (y_coord < 525);DE_out <= DE_generated_from_screen_coords;You would make DE directly from my first expression if the picture data also resolves in 1 clock. If you are looking up a RAM using the screen coords, then you would use both expressions, or even an additional DE delay to accommodate the ram read delay.As for the syncs, something like this:HS_generated_from_screen_coords <= (x_coord >= 816) && (x_coord < 848);VS_generated_from_screen_coords <= (y_coord >= 482) && (y_coord < 485);And if you want, delay or not the HS/VS outputs to keep a perfect parallel sync timed image pipe.I left in enough room so you may try wrapping around your H&V coord counter to 0-999 & 0-499 to make a 60Hz display with a 30MHz pixel clock.

author: Miti
author_rank: Super Contributor
timestamp: April 12, 2021, 02:24:48 am
content: BTW, the differential lines must be pulled low or kept tristate until the supply voltage is stable. Cyclone LVDS outputs cannot be pulled low or tristated. Should I pull nCONFIG low until the supply voltage reaches 3V?In my experiments it doesn’t seem to care but the data sheet says it can get damaged.

author: BrianHG
author_rank: Super Contributor
timestamp: April 12, 2021, 02:48:30 am
content: Quote from: Miti on April 12, 2021, 02:24:48 amAre you talking about the display being damaged?I need to double check on the tristate. I know it's been added to the MAX10 IO, but I am not sure about the older Cyclones. If you are using the LVDS_E_3R IO standard, yes, those can be tristated. I'm just not sure about the authentic 'LVDS'.You will need to initiate the ALTIOBUFF to get the tristate working with differential.The 4-outputs of the altlvds_tx will feed the altiobuff which will give you 4 OEs for the P and 4 OEs for the N pins, and outputs 4xP & 4xN. I know currently, you might have assigned the differential outputs VIA pin assignment, calling the IOBUFF forces it and provides both the P&N outputs which you can name each the way you like.Yes, holding the nCONFIG low is another method to guarantee dead IOs until you allow the bootprom to load.However, I think the reset state has the IOs with a weak pullup. Most likely not strong enough to damage the receiver IC in the display, we are talking 100k-200k to VCCIO.Essentially, if the display is powered up with the FPGA, you shouldn't have trouble here. If the display is separately powered, then I recommend you should have a display detect and keep the IOs in tristate when the display is powered down but still connected. This is typically the same with DVI/HDMI as the transmitter ICs use the display sense pin and shut-down their output when there is no 5v present on the pin.

author: Miti
author_rank: Super Contributor
timestamp: April 12, 2021, 03:05:53 am
content: Check Note2 on page 10.

author: BrianHG
author_rank: Super Contributor
timestamp: April 12, 2021, 03:26:26 am
content: Yes, do not drive output current until the VCC has passed 3v.Scope your power rails and check when the LVDS outputs begin to drive current compared to when the VCC for the panel passes 3v.The power-up and boot time for the FPGA might clear the time for you here.If the above timing is ok, but you designed your panel to be powered down while the FPGA remains on, then you will need to be concerned about this.My brown-out reset circuit on the nCONFIG would definitely add and beyond clear this time for you, as well as cut the FPGA's IO ahead of a power drop as it senses the drop from the 5v source feeding your 3.3v switcher before the 3.3v even begins to drop.

author: SMB784
author_rank: Frequent Contributor
timestamp: April 12, 2021, 02:29:52 pm
content: Quote from: BrianHG on April 12, 2021, 03:26:26 amMy understanding of the FPGA boot sequence is that when nCONFIG (I think also called CONF_DONE in other units) will only go high once the power rails have reached a stable voltage, e.g. 3.3vSee fig 3b (erroneously labelled as fig 3a in the description) in attached PDF for what I am talking about in a Max10 FPGA

author: BrianHG
author_rank: Super Contributor
timestamp: April 12, 2021, 03:05:46 pm
content: Quote from: SMB784 on April 12, 2021, 02:29:52 pmnCONFIG is an input used to completely clear and reboot the FPGA as well as one of the programmer lines. Tying it low will clear the active configuration memory and when released, the FPGA will reboot from the bootprom or JTAG.CONF_DONE is an output telling you that the FPGA has finished booting.Both are on the MAX10 as well as all Altera FPGAs.My super slow power-on reset and brown-out circuit here:https://www.eevblog.com/forum/fpga/how-to-eliminate-a-reset-input/msg3488338/#msg3488338Scope shots are also on the page in subsequent and prior posts.

author: Miti
author_rank: Super Contributor
timestamp: April 13, 2021, 12:07:18 am
content: Quote from: BrianHG on April 12, 2021, 02:24:34 amYou are right, I was looking at DE vs coordinates, when I should have look at DE vs colour data. All I need to do was to delay DE one clock through a register and I can see all pixels now, from 0 to 799and from 0 to 479.Next is to see how tolerant it is to various pixel counts.Cheers and beers to all who helped!

author: Miti
author_rank: Super Contributor
timestamp: April 13, 2021, 10:48:56 am
content: Just a quick question, how do you add Altera mega functions to Modelsim? I can’t find Altlvds or Altpll in it.

author: BrianHG
author_rank: Super Contributor
timestamp: April 13, 2021, 11:19:25 am
content: Quote from: Miti on April 13, 2021, 10:48:56 amOn the vsim compile line, add:Code:vsim -t 1ps -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L altera_lnsim_ver -L cycloneive_ver -L work -voptargs="+acc" Yout_test_bench_module_nameAll the '-L' includes the Altera libraries and the '-L cycloneive_ver' makes sure that the Cyclone IV-E versions of the megafunctions are used.2 examples:This code set-s up Modelsim to compile and simulate my DDR3 controller, I call is 'setup_phy.do':Code:transcript onif {[file exists work]} {vdel -lib work -all}vlib workvmap work workvlog -sv -work work {BrianHG_DDR3_GEN_tCK.sv}vlog -sv -work work {BrianHG_DDR3_PLL.sv}vlog -sv -work work {BrianHG_DDR3_PLL_tb.sv}vlog -sv -work work {BrianHG_DDR3_IO_PORT_ALTERA.sv}vlog -sv -work work {BrianHG_DDR3_PHY_SEQ.sv}vlog -sv -work work {BrianHG_DDR3_PHY_SEQ_tb.sv}#Enable this VSIM for all cyclone parts.vsim -t 1ps -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L altera_lnsim_ver -L cycloneive_ver -L work -voptargs="+acc" BrianHG_DDR3_PHY_SEQ_tbrestart -force -nowave# This line shows only the variable name instead of the full path and which module it was inconfig wave -signalnamewidth 1#add wave /BrianHG_DDR3_PHY_SEQ_tb/* (IF this line was not commented out, every signal in the tb would be added to the waveform)add wave -divider "Script File"add wave -ascii /BrianHG_DDR3_PHY_SEQ_tb/TB_COMMAND_SCRIPT_FILEadd wave -decimal /BrianHG_DDR3_PHY_SEQ_tb/Script_LINEadd wave -ascii /BrianHG_DDR3_PHY_SEQ_tb/Script_CMDadd wave -divider "RST/CLK_in"add wave -hexadecimal /BrianHG_DDR3_PHY_SEQ_tb/RST_INadd wave -hexadecimal /BrianHG_DDR3_PHY_SEQ_tb/CLK_INadd wave -hexadecimal /BrianHG_DDR3_PHY_SEQ_tb/RESETadd wave -hexadecimal /BrianHG_DDR3_PHY_SEQ_tb/PLL_LOCKEDadd wave -divider "DDR3 SEQ CMD Input"add wave -hexadecimal /BrianHG_DDR3_PHY_SEQ_tb/SEQ_BUSYadd wave -hexadecimal /BrianHG_DDR3_PHY_SEQ_tb/CMD_CLKadd wave -hexadecimal /BrianHG_DDR3_PHY_SEQ_tb/SEQ_CMD_ENAadd wave -hexadecimal /BrianHG_DDR3_PHY_SEQ_tb/SEQ_WRITE_ENAadd wave -hexadecimal /BrianHG_DDR3_PHY_SEQ_tb/SEQ_ADDRadd wave -hexadecimal /BrianHG_DDR3_PHY_SEQ_tb/SEQ_WMASKadd wave -hexadecimal /BrianHG_DDR3_PHY_SEQ_tb/SEQ_WDATAadd wave -hexadecimal /BrianHG_DDR3_PHY_SEQ_tb/SEQ_RDATA_VECT_INdo run_phy.doThis code is the 'run_phy.do', I only need to run the 'do setup_phy.do' once, then, every time I edit my code, I just 'do run_phy.do' to recompile and restart the simulation:Code:vlog -sv -work work {altera_gpio_lite.sv}vlog -sv -work work {BrianHG_DDR3_GEN_tCK.sv}vlog -sv -work work {BrianHG_DDR3_PLL.sv}vlog -sv -work work {BrianHG_DDR3_PLL_tb.sv}vlog -sv -work work {BrianHG_DDR3_IO_PORT_ALTERA.sv}vlog -sv -work work {BrianHG_DDR3_PHY_SEQ.sv}vlog -sv -work work {BrianHG_DDR3_PHY_SEQ_tb.sv}restart -forcerun -allwave cursor activewave refreshwave zoom range 0ns 5000nsview signalsEvery once-in-awhile some big code change will not quick re-compile where I need to just re-run the 'setup_phy.do'.Note that the _phy is for simulating the 'PHY' section of my memory controller and I have a few other setup_xxx.do/run_xxx.do files to simulate different sections of my code and show different waveforms.

author: Miti
author_rank: Super Contributor
timestamp: April 17, 2021, 02:24:21 pm
content: And just because I can, a bit of picture-in-picture exercise. Unscaled, of course, because video scaling is way out of my league.

author: BrianHG
author_rank: Super Contributor
timestamp: April 17, 2021, 05:38:59 pm
content: Quote from: Miti on April 17, 2021, 02:24:21 pmNo, it is not...You just need to think things through.Begin with input res and output res & what X&Y factor you wish.Second hint, for the Y output, you will want access to 2 different/adjacent Y coordinates of video simultaneously, but, begin with a variable X scale all by itself.

author: SiliconWizard
author_rank: Super Contributor
timestamp: April 17, 2021, 05:47:17 pm
content: Quote from: Miti on April 17, 2021, 02:24:21 pmSo are you working on a display replacement for an old HP spectrum analyzer?

author: Miti
author_rank: Super Contributor
timestamp: April 17, 2021, 05:59:10 pm
content: Quote from: SiliconWizard on April 17, 2021, 05:47:17 pmIt's almost done but this is not related, the LVDS was just a learning exercise.Take a look here for the CRT replacement:https://www.eevblog.com/forum/projects/hp-8594e-replacing-the-green-crt-with-lcd/Covid slew down my prototyping to a halt. I just need to figure out the cables and the mounting and I will offer it for sale. Not sure if there's much interest though.Again, this project was also a combination of learning and making something useful, as I want to replace my SA's CRT.

author: BrianHG
author_rank: Super Contributor
timestamp: April 17, 2021, 06:18:36 pm
content: Just so we are clear, you can begin scaling with just adding a few numbers to your existing code.

author: SiliconWizard
author_rank: Super Contributor
timestamp: April 17, 2021, 06:24:19 pm
content: Quote from: Miti on April 17, 2021, 05:59:10 pmI have worked on something similar for a Lecroy 9354AL scope. I've also put this project on hold so it's not quite finished, but I was able to get images directly from the display processor with colors from what originally had a monochrome CRT. (The display processor actually puts out color data, but the CRT and its controller is only monochrom - albeit with this nice amber tone.)As this has an odd resolution of 810x696, it would also require scaling in order to get a full-size image on the 1024x768 LCD panel I chose.BrianHG makes it sound like it's very simple stuff, but merely copying values to adjacent pixels - if that's what they suggest - will look horrible. It takes at least some bilinear interpolation to get something acceptable. Maybe this is what Brian suggested though, and it's true it's not that hard, but you still have to make this work at the pixel clock.

author: BrianHG
author_rank: Super Contributor
timestamp: April 17, 2021, 06:47:48 pm
content: Quote from: SiliconWizard on April 17, 2021, 06:24:19 pm1 step at a time... First, beginner steps, a fractional variable X&Y scale.Then bi-linear, then optionally bi-cubic comes next...

author: Miti
author_rank: Super Contributor
timestamp: April 18, 2021, 01:49:44 pm
content: Quote from: SiliconWizard on April 17, 2021, 06:24:19 pmFor me it was much easier, the input image is 512 x 256 pixels with two brightness levels, the output is 1024 x 768. All I had to do was to display the same pixel twice on the horizontal and three times on the vertical and output that to a VGA output. It keeps the aspect ratio exactly as on the original CRT. I let the LCD controller do the interpolation.I digitize the two levels video using LVDS inputs and with Brian's help, I recover the video clock from the horizontal sync using a very clever digital PLL scheme. The frame buffer is in the FPGA RAM. All very compact, you can see how simple the board is in one of the pictures in that thread.

author: Miti
author_rank: Super Contributor
timestamp: April 18, 2021, 01:57:57 pm
content: Quote from: BrianHG on April 17, 2021, 05:38:59 pmOk, so the input image is 512 x 256 pixels and my LVDS LCD is 800 x 480. I need to stretch the input to 640 x 480 to maintain the correct aspect ratio and, eventually, center it but that's easy.So the X factor would be 640/512 = 1.25 and the Y factor is 480/256 = 1.875.

author: BrianHG
author_rank: Super Contributor
timestamp: April 18, 2021, 02:27:54 pm
content: Quote from: Miti on April 18, 2021, 01:57:57 pmOk, this is a start.Next, when generating the picture output, what does your current code look like?Can you think of a stupid way you may variably stretch the output pixels of the X & Y axis by any arbitrary fractional amount just by adding an X & Y scale factor and moving around a number or register size?(I can assure you, it should be so simple stupid that you may use your analog sampled POT input to variably stretch the image in real time...)

author: BrianHG
author_rank: Super Contributor
timestamp: April 18, 2021, 04:14:14 pm
content: If it's taking you more than 5 minutes to figure it out and 1 minute to code, you are going about it wrong...

author: Miti
author_rank: Super Contributor
timestamp: April 18, 2021, 05:11:29 pm
content: One way I can think of is to divide the LCD position by the scaling factor, round it to the nearest integer, and read from the buffer at that address.The VGA Controller code is attached.Code:moduleVGA_Controller(//Host SideiRed,// Red input from pattern generator or frame bufferiGreen,// Green input from pattern generator or frame bufferiBlue,// Blue input from pattern generator or frame bufferoAddress,// Read address to the frame bufferoCoord_X,oCoord_Y,//VGA SideoVGA_R,oVGA_G,oVGA_B,oDE,oDebug1,oDebug2,//oVGA_H_SYNC,//oVGA_V_SYNC,//Control SignaliCLK,iRST_N);//`include "VGA_Param.h"`include "Video_Param.h"parameter H_Total= 1024;parameter H_Active= 800;parameter V_Total= 525;parameter V_Active= 480;parameter Video_H= 512;parameter Video_V= 256;//Host Side//outputreg[16:0]oAddress;//outputreg[10:0]oCoord_X;//outputreg[9:0]oCoord_Y;output[16:0]oAddress;output[10:0]oCoord_X;output[9:0]oCoord_Y;outputoDebug1;outputoDebug2;input[9:0]iRed;input[9:0]iGreen;input[9:0]iBlue;//VGA Sideoutput[9:0]oVGA_R;output[9:0]oVGA_G;output[9:0]oVGA_B;//outputregoVGA_H_SYNC;//outputregoVGA_V_SYNC;//Control SignalinputiCLK;inputiRST_N;//Internal Registers and Wiresreg[10:0]H_Count;reg[9:0]V_Count;reg[10:0]Cur_Color_R;reg[10:0]Cur_Color_G;reg[10:0]Cur_Color_B;//wiremCursor_EN;output regoDE;regoDE_Temp;assignoVGA_R=(H_Count <= H_Active + 1'b1 && V_Count < V_Active) ?Cur_Color_R:10'd0;assignoVGA_G=(H_Count <= H_Active + 1'b1 && V_Count < V_Active) ?Cur_Color_G:10'd0;assignoVGA_B=(H_Count <= H_Active + 1'b1 && V_Count < V_Active) ?Cur_Color_B:10'd0;assign oCoord_X = (H_Count < H_Active && V_Count < V_Active) ? H_Count : 11'd1023;assign oCoord_Y = (H_Count < H_Active && V_Count < V_Active) ? V_Count : 11'd824;assign oAddress = (H_Count <= Video_H && V_Count <= Video_V) ? oCoord_Y * Video_H + oCoord_X: 17'd0;assign oDebug1 = (H_Count == 0) ? 1'b1 : 1'b0;assign oDebug2 = oDE;// DE Output Delayalways@(posedge iCLK or negedge iRST_N)beginif(!iRST_N)// If Reset button is pressedbeginoDE<=1'b0;// Clear DE output at resetend// if(!iRST_N)elsebeginoDE <= oDE_Temp;endend//Cursor Generatoralways@(posedge iCLK or negedge iRST_N)beginif(!iRST_N)beginCur_Color_R<=11'd0;Cur_Color_G<=11'd0;Cur_Color_B<=11'd0;endelsebeginCur_Color_R<=iRed;Cur_Color_G<=iGreen;Cur_Color_B<=iBlue;endend//H Counteralways@(posedge iCLK or negedge iRST_N)beginif(!iRST_N)// If Reset button is pressedbeginH_Count<=11'd0;// Clear horizontal pixel counter at resetoDE_Temp<=1'b0;// Clear DE output at resetend// if(!iRST_N)elsebegin//H Counterif( H_Count < H_Total)// Counter didn't reach the end of the line (visible + invisible)H_Count<=H_Count + 1'b1;// Increment the horizontal pixel counterelseH_Count<=11'd0;// Reset the counter and start a new line//H_Sync Generatorif( H_Count < H_Active && V_Count < V_Active)// Within the active windowoDE_Temp<=1'b1;// Data Enable goes HIelseoDE_Temp<=1'b0;// Data Enable goes LOendend//V Counteralways@(posedge iCLK or negedge iRST_N)beginif(!iRST_N)// If Reset button is pressedbeginV_Count<=10'd0;// Clear vertical line counter at resetendelsebegin//When H_Sync Re-startif(H_Count == H_Total - 1'b1)// Increment or reset the line counter at the beginning of the line (Miti: H_Cont and V_Cont are not in sync)begin//V_Sync Counterif( V_Count < V_Total )// Counter didn't reach the end of frame (visible + FP + BP)V_Count<=V_Count + 1'b1;// Increment the vertical line counterelseV_Count<=10'd0;endendendendmodule

author: BrianHG
author_rank: Super Contributor
timestamp: April 18, 2021, 05:23:00 pm
content: There is nothing wrong with this code. It does not need modifying.Where is the code which places you sampled video bitmap on the screen.The part which shows the ram.How do you point the the pixel you want to show?Where are those X&Y counters?

author: Miti
author_rank: Super Contributor
timestamp: April 18, 2021, 05:55:56 pm
content: Quote from: BrianHG on April 18, 2021, 05:23:00 pmoAddress is the read address of the dual port RAM frame buffer.

author: BrianHG
author_rank: Super Contributor
timestamp: April 18, 2021, 06:12:58 pm
content: Ok, so:Code:assign oCoord_X = (H_Count < H_Active && V_Count < V_Active) ? H_Count : 11'd1023;assign oCoord_Y = (H_Count < H_Active && V_Count < V_Active) ? V_Count : 11'd824;assign oAddress = (H_Count <= Video_H && V_Count <= Video_V) ? oCoord_Y * Video_H + oCoord_X: 17'd0;Step 1, get rid of the first 2 lines, make oCoord_X & oCoord_Y normal registers and stuff them into:Code://H Counteralways@(posedge iCLK or negedge iRST_N)beginANDCode://V Counteralways@(posedge iCLK or negedge iRST_N)beginSo they literally run in parallel with H_Count and V_Count.Make it like you are running the H&V counter code twice.Next step, what would happen to your output image if you increase the bit width of oCoord_X and oCoord_Y by 1, then for this line, you do:Code:assign oAddress = (H_Count <= Video_H && V_Count <= Video_V) ? oCoord_Y[11:1] * Video_H + oCoord_X[10:1] : 17'd0;Now, tell me what would happen if you increase the bits of oCoord_X&Y by 16 and change that line to:Code:assign oAddress = (H_Count <= Video_H && V_Count <= Video_V) ? oCoord_Y[26:16] * Video_H + oCoord_X[25:16] : 17'd0;

author: BrianHG
author_rank: Super Contributor
timestamp: April 18, 2021, 06:56:51 pm
content: Ok, it would have looked nicer if your code was also not separated into H & V sections.

author: Miti
author_rank: Super Contributor
timestamp: April 18, 2021, 07:25:43 pm
content: Quote from: BrianHG on April 18, 2021, 06:12:58 pmIt would stretch the image by a factor of 2, the first line, and by 65536 the second line?I think there's a mistake in the length of the registers, X is longer by 1.So what you meant was:Code:assign oAddress = (H_Count <= Video_H && V_Count <= Video_V) ? oCoord_Y[10:1] * Video_H + oCoord_X[11:1] : 17'd0;assign oAddress = (H_Count <= Video_H && V_Count <= Video_V) ? oCoord_Y[25:16] * Video_H + oCoord_X[26:16] : 17'd0;Edit: I think I know where you're going. You stretch the image a lot, then you make a divider and squeeze it back by a number that would give you the desired fractional scale factor, without using float division.

author: BrianHG
author_rank: Super Contributor
timestamp: April 18, 2021, 07:36:41 pm
content: Sorry, no divider needed...Next step:What would happen for the +1 bit setting if in the counter section, you changed the 'oCoord_X <= oCoord_X+ 1' to a '+ 2' ?What would happen for the +16 bit setting if in the counter section, you changed the '+ 1' to a '+ 65535' ?Again, for the +16 bits section, change the '+ 1' to '+ 32768' ?What about any other number?How about wiring the ADC of your volume control knob into the '+ 1' so that it goes from 0 -> 65535, what would happen then?Nothing but simple addition...

author: BrianHG
author_rank: Super Contributor
timestamp: April 18, 2021, 07:58:22 pm
content: Quote from: Miti on April 18, 2021, 07:25:43 pmThis is from your original code:QuoteSince you had 'oCoord_X' at [10:0], I just added 1 to both creating a left-shift by 1 bit.

author: Miti
author_rank: Super Contributor
timestamp: April 18, 2021, 08:31:18 pm
content: Quote from: BrianHG on April 18, 2021, 07:36:41 pmThis happens:Man, I envy smart people...It doesn't look too bad even without interpolation.

author: BrianHG
author_rank: Super Contributor
timestamp: April 18, 2021, 09:07:58 pm
content: You are doing fine. I just have experience with fixed floating point & resizing graphics.You can use different scale sizes for the X&Y to stretch fill the image on the LCD.Now, bi-linear filtering is not that more complicated, but, it does require a bit of ingenuity.(This is considered for thought and experimentation. I'll offer further in a day or so if you wish, though, you might be able to solve the problem for yourself...)Your 'oCoord_X/Y[25:16]' contains an integer location of which pixel you wish to draw on the output display.And if you think it through, your 'oCoord_X/Y[15:0]' contains a fractional location in-between the current integer location and the next integer location of the pixel you wish to draw. (You may consider only using oCoord_X/Y[15:8] for 255 sub-locations between the current integer pixel and the adjacent one.)This means, when reading a pixel, you want to have simultaneous access to 4 pixels decoded as RGB color after your palette. Pixels oCoord_X/Y, oCoord_X+1/Y, oCoord_X/Y+1, oCoord_X+1/Y+1. The oCoord_X/Y[15:8] will be like a linear fader/selector multiplying how much of X/Y, X+1/Y, X/Y+1, X+1/Y+1 is blended together, with the sum result being your final pixel.EG, everything (RGB) is 3x, this is not proper code, it is an example guide (the math was for 24 bit color, you can shrink everything from 8 bits to 4 bits for 12 bit accuracy):Code:assign x_fraction = oCoord_X[15:8];assign y_fraction = oCoord_Y[15:8];out_y0(RGB) <= ( (oCoord_X/Y[25:16]_(RGB) * (255-x_fraction)) + (oCoord_X+1/Y[25:16]_(RGB) * (x_fraction)) ) >> 8 ;out_y1(RGB) <= ( (oCoord_X/Y+1[25:16]_(RGB) * (255-x_fraction)) + (oCoord_X+1/Y+1[25:16]_(RGB) * (x_fraction)) ) >> 8 ;out_final(RGB) <= ( (out_y0(RGB) * (255-y_fraction)) + (out_y1(RGB) * (y_fraction)) ) >> 8 ;The trick is how to get the 4 correct pixels at every pixel clock cycle.There are a few solutions.For the Y coordinate, one trick is to break up your display ram buffer into 2 dual port ram blocks. 1 block will hold all the even Y lines of the picture while the second will store all the odd Y line. On the read side, with a little smart steering logic based on requested address and which data you read, you may now read an even and odd Y line simultaneously. This solves simultaneous reading of Y and Y+1. The same can be done for the X / or vertical lines. This means 4 dual port rams, each with 1/2 the X size and 1/2 the Y size.There are smarter ways to do the X without 4 rams since you know you are always reading from left to right. Also, for the Y, you may also run the read side at 2X speed feeding the Y address and then the Y+1 address.

author: BrianHG
author_rank: Super Contributor
timestamp: April 18, 2021, 09:29:20 pm
content: Quote from: Miti on April 18, 2021, 08:31:18 pmIn your LCD shot, it looks as if you only stretched the Y axis and not the X...

author: Miti
author_rank: Super Contributor
timestamp: April 18, 2021, 10:19:08 pm
content: Quote from: BrianHG on April 18, 2021, 09:29:20 pmThe LCD module is 800x480, my image is stretched to 640x480. Look at the grid, it is square now.

author: Miti
author_rank: Super Contributor
timestamp: May 08, 2021, 01:38:26 am
content: Ok, I know I deviate from the subject but since I started the discussion here, I’ll continue a bit.I figured out what was wrong with Xilinx ISE not starting. I looked at the shortcut that was created on the desktop, and rather than starting an exe file, it points to a bat file. I copied the command in the shortcut and I ran it in a command line and it tried to open python27, which wasn’t installed. Once I installed it and renamed it from pyton.exe to python27.exe, it started. Hurray!!!However, it cannot find a license for ISE features, even though I installed one. 🤦‍♂️Why does Xilinx ISE need Python 2.7 to run? Oy vey!

author: SiliconWizard
author_rank: Super Contributor
timestamp: May 08, 2021, 05:28:54 pm
content: Quote from: Miti on May 08, 2021, 01:38:26 amISE seems to use Python indeed. There are a few Python modules in the Xilinx\14.7\ISE_DS\ISE\bin\nt64 directory. Not sure what they are there for. But the required Python support should be installed by the ISE installer. Dunno what happened in your case.

author: Miti
author_rank: Super Contributor
timestamp: January 20, 2024, 10:50:55 pm
content: A member of this forum asked me to post the code and here it is. It does what's in the picture attached.You need to rename from _01.zip to .zip.001 and so on and unzip.Cheers,Miti

author: Miti
author_rank: Super Contributor
timestamp: January 20, 2024, 10:51:57 pm
content: Second part.