LCD controller on FLGA. Altera. - Page 1
Forum section: electronics / general

author: Buriedcode
author_rank: Super Contributor
timestamp: June 29, 2016, 01:50:20 pm
content: So After a clear out I found a Cyclone II board, a USB blaster, and decided to do soemthign I've been meaning to do for ages - make a basic LCD controller to replace the s1d13700/SED1335. I have many LCD's all with slightly different requirements, so I thought an FPGA running a basic processor (nios II) and some custom logic, external memory, I could make a controller I can configure and use as a display tester. The nios II is really just there to make it easier to modify the test patterns and provide a simple C program for options.Its an old FPGA so I had to use Quartus II v13. I did a tutorial - my 'first nois II project' and it went well proving the board, programming cable and design flow works. It spat out the state of a timer through the jtag debug console.I tried to add my own SOPC component based off 'on board memory', so the verilog file it produces has an 'avalon slave' interface. I then modified the memory config to be dual port RAM, added the second interface, which is controlled a by a few counters that creates the Vsync, and Hsync, pixel clock etc.. but given I was doing a lot in one go, alas, I'm getting errors all over the show. Probably because using 'qsys' whenever I modify a components verilog source, I have to reload it, but it still tries to find components I removed.So rather than the vague 'I get erorr, what do I do?' question (its clearly my lack of understanding rather than the software) I'm asking for relatively simple Quartus II projects that I can learn by example. If anyone has any custom peripherals that the nios II processor can control, I would be grateful if you could share. Ideally, a peripheral that uses memory blocks - that can be written to/read by the nios II, but also accessed by custom logic in verilog. I have googled my heart out on this one but find either sources for character LCD's, large TFT's (which has a very simple interface) or stuff written in VHDL.

author: Buriedcode
author_rank: Super Contributor
timestamp: June 30, 2016, 11:59:35 am
content: Well, since my question in my first post was both vagueandoverly specific (graphic LCD controller for STN, not all that common) rather than create another topic, I'll start with asking questions that can help me move along. Although I studied basic programmable logic at university (some 13 years ago..CPLD's, state machines etc..) I'm getting back into it because, well, its a handy skill to have, plus theres an ever growing list of my own projects that I think could benefit from it. So bear with me as its quite basic stuff.I decided to make a basic pipeline, where the block is clocked at 8x the pixel clock, giving me 8 clock cycles between writes, so a state machine/pipeline that performs tasks sequentially before every write to the LCD. I am aware that is is best not to divide down the input clock to clock other logic, but have it all clocked by the same clock, so the first port of call is a simple 3-bit counter that outputs single pulses when the counter is 000, 001, 010 etc.. then use these as 'enable' lines to the various parts. I fell at the first hurdle.Code:parameter ScreenWidth = 6;parameter ScreenHeight = 6;reg[ 7:0] CounterX;reg[ 7:0] CounterY;wireoutupdate;wirehalfway_pipe;wirepix_strobe;reg [2:0] state_count;wire CounterXmaxed = (CounterX==ScreenWidth/4-1);wire CounterYmaxed = (CounterY==ScreenHeight-1);assign outupdate = (state_count == 0);assign halfway_pulse = (state_count == 4);assign pix_strobe = (state_count == 0);always @(posedge clk)beginstate_count <= state_count +1;if (outupdate)pxlclkout <= 1;else if (halfway_pulse)pxlclkout <= 0;endalways @(posedge clk)beginif (outupdate)beginif(CounterXmaxed)CounterX <= 0;elseCounterX <= CounterX + 1;endendalways @(posedge clk)beginif (outupdate)beginif(CounterXmaxed)beginif(CounterYmaxed)CounterY <= 0;elseCounterY <= CounterY + 1;endendend'pxlclkout' produces 50% duty cycle at clock/8 as expected, so the 'state_counter' is counting, and 'outupdate' must produce a single pulse, one clock period, when the counter is 000. Same goes for halfway_pulse at state_count == 4. The 'pix_strobe' is redundant but I just added it as an output signal for testing. CounterXmaxed remains high, and CounterX does not change. However, CounterY does increment, and indeed produces a pulse - one CounterX period wide, every 6 pxlclkouts. So counterY is counting as CounterX should.CounterY should only be incremented when counterX rolls over. I didn't use a single counter because I would like to be able to change the resolution later on for configuring it to work with different LCD's.I'm probably missing something obvious, and 'asking on a forum' is down in the list of things to try, but I just can't see where I'm going wrong here. Thanks!

author: Buriedcode
author_rank: Super Contributor
timestamp: June 30, 2016, 12:34:16 pm
content: Ok.. rather than edit the above, or remove it I left it so others could see my mistake. I knew it would be something simple - I'm a dumber.The parameter 'CounterXmaxed = Screenwidth/4 -1. I was testing it with 'Screenwidth = 6'. So of course this evaluated to 1 - 1 = 0. Therefore CounterXmaxed would be high if the counter was 000 - it was permanently high because this prevented it from incrementing.CounterY on the other hand, was simply incremented every 'outupdate' pulse, because counterXmaxed - used as a single pulse counter enable, was always high, so it counted at the rate of 'outupdate', which was clk/8.This is why one should hard code absolute parameters such as 'max count' during testing. Starting simple so you *know* that a constant is a constant - and not gone through even a relatively simple equation. Otherwise you risk assuming it is, but it gets evaluated to something silly, like 0.

author: AndyC_772
author_rank: Super Contributor
timestamp: June 30, 2016, 01:30:53 pm
content: Thanks for taking the time to post a solution as well as the problem; I wish more people would bother.I've been using Altera FPGAs for years but never got into Qsys or Nios. To me, buying expensive FPGA logic and then putting a microcontroller in it never seemed like a very compelling option, when I can just use a separate PIC or ARM processor. Have you found a major benefit in using an embedded CPU?

author: Buriedcode
author_rank: Super Contributor
timestamp: June 30, 2016, 01:44:42 pm
content: Quote from: AndyC_772 on June 30, 2016, 01:30:53 pmUltimately the processor is there just to make it easier for me to test the custom LCD hardware. It provides a relatively simple (albeit totally inefficient) testbed, using one of the example projects as a template, to write bytes to on-board memory - which is dual ported so the LCD controller can use it as a frame buffer. If I was just to ahve the LCD controller, I would need to hook up either a microcontroller, or a USB-serial bridge to be a data source. I thought, even though its an old device (Cyclone II..), if its got enough room for the most stripped down NIOS II available, I might as well add that in and use it as a debug interface too.Like using a dedicated LCD controller (epson etc..) one still needs to provide data to 'draw' on the screen.. I was just killing two birds with one stone - learn to use it for future reference, and have it as a simple interfaceI've only given it 12kbytes of memory. It's also prudent to learn how to attach things to the avalon bus evetually producing custom peripherals that are easily accessed by code.

author: Buriedcode
author_rank: Super Contributor
timestamp: June 30, 2016, 10:24:07 pm
content: Andy, may I ask what sorts of projects/contracts you use FPGAs for? Whilst I'm not totally new to the field, and have watched it grow and grow over the last 15 years or so, aside from telecoms/fibre and high speed interconnect, I haven't seen many 'middle ground' applications. Sure there's plenty in the application notes - using processor cores, as a second MCU, but actual real-world designs using smaller FPGAs/CPLD. Perhaps I'm just not looking hard enough - I think I've only seen FPGA's in a couple of commercial projects, and a few CPLD's in some just for interfacing.

author: Buriedcode
author_rank: Super Contributor
timestamp: July 04, 2016, 02:57:29 pm
content: Again, another question, this time quite specific to the cyclone II - or maybe all Altera devices using quartus II.I have SDRAM on the board I have, with the SDRAM's clk line on pin 151 of the FPGA, according to the datasheet, that pin is the direct output from c2 of PLL2. I'm assuming this was done intentionally so the SDRAM can be clocked directly by the PLL, allowing one to adjust clock skew relative to the other PLL outputs.In qsys, I exported the PLL's C2 signal out, and on my high level schematic, connect that to the relevant pin. However, quartus II kicks up a fuss about it being routed through 'non-dedicated logic' - so I'm assuming it doesn't enable the PLL output on that pin directly, but rather treats it as a user IO, which is then hooked to the PLL output. Heres the warning (note, after hours of fiddling about with pinouts, I can read/write to the SDRAM)Code:Warning (15064): PLL "LCDcntrl:inst2|LCDcntrl_RAMPLL:rampll|altpll:sd1|pll" output port clk feeds output pin "SDRAM_CLK" via non-dedicated routing -- jitter performance depends on switching rate of other design elements. Use PLL dedicated clock outputs to ensure jitter performanceI have read several posts on Altera forums with the only answer given as 'just routed the PLL output to the pin' - which doesn't help at all. I used qsys to set up the PLL because it is also used to clock the SDRAM controller (100MHz), nios II (50MHz), and of course the SDRAM (100MHz, - 3ns). Does anyone have example code for hooking up SDRAM to a cyclone II?

author: AndyC_772
author_rank: Super Contributor
timestamp: July 04, 2016, 03:27:52 pm
content: Sorry, I missed your earlier question.The simple answer is that I use FPGAs wherever I'm doing something interesting in logic which isn't a standard function built into a CPU. So, for example, if you need many channels of <whatever>, an FPGA is the way to go.Or, perhaps you need to support a legacy or non-standard protocol that your chosen CPU doesn't do.I use them to generate stimuli in sensor applications, and then to capture and process the results before presenting them as a neatly formatted data packet to the host CPU. It's much easier to co-ordinate a timed sequence of events in an FPGA than it is to try and program general purpose timers, counters and interrupt handlers to do the same thing in a CPU, and if you need absolutely guaranteed cycle-to-cycle timing relationships to be maintained, there's really no other option.Re: your PLL question, do you know for sure that the PLL you've configured is actually PLL2? If the one you've instantiated hasn't been allocated to PLL2, its outputs won't appear on the right pins.

author: Buriedcode
author_rank: Super Contributor
timestamp: July 04, 2016, 04:01:00 pm
content: Quote from: AndyC_772 on July 04, 2016, 03:27:52 pmAhh thank you! I have asked quite a few 'FPGA guys' about this and it was either very specific (they had one product that dealt with telecomms) or 'oh I don't use them at work, just hobby'. I have only used basic CPLD's for actual contracts, and just like your description it was pretty much for legacy products or awkward one-off's with lots of IO where the number of shift registers outweighed the benefit of a single device.Quote from: AndyC_772 on July 04, 2016, 03:27:52 pmExcellent question, I assumed (never a good thing..) it was PLL2 because the dedicated PLL2_OUT pin is in the same IO bank as the SDRAM connections (again using built in megafunction). But read that sentence back - it just seems silly. The 'ATPLL wizard' makes no mention of which actual PLL used, nor anything about enabling dedicated output. I'll have to dig into qsys's generated files (yay..) to find any references to it.. My 'test' project is working, or at least appears to be. Uses the 'memtest' example code for the NIOS II which writes known patterns to a fixed range of addresses (absolute) and reads them back. Takes a few seconds for 128MBit of SDRAM but I suspect that is just because the NIOS II is the most basic kind and running at 50MHz.Thank you again sir, I'll have a poke around in the 'sea' of files this software generates..Edit: My input clock is Pin23 which is CLK0. SO I guess that seals the deal as an Altera app note on the PLL in these devices implicitly states CLK0-3 is for PLL1, and 4-7 for PLL2. Looks like I'm gonna have to add a second clock..

author: Kilrah
author_rank: Unknown
timestamp: July 04, 2016, 04:44:15 pm
content: If you watch Dave's recent test equipment teardowns you'll see that most recent scopes have at least one FPGA or FPGA-containing SoC like the Zynq pretty much at any price point.The current crop of devices having made a big step towards fast acquisition and update the data has to be processed and pushed to the display more quickly than it could if it had to go through the main application processor, so the latter only renders the UI elements and the actual waveform is shoved straight into the display buffer by an FPGA (that usually implements the display controller while it's there too). Guess that's a category of device that doesn't really make it viable to roll out an ASIC (too many differences in capability between models and too much competition = can't make a common part for all), and combined with the price drop for low-mid range FPGAs that makes them a good choice.

author: AndyC_772
author_rank: Super Contributor
timestamp: July 04, 2016, 09:16:47 pm
content: I usually design products that are made in quantities of 10's to 1000's. The idea of using an ASIC is so far away it's not even funny...!

author: Buriedcode
author_rank: Super Contributor
timestamp: July 06, 2016, 06:49:38 pm
content: Might as well add progress! Whilst the board I have is, as I've said - super basic - they were smart enough to route the on-board oscillator to two CLK inputs, either side of the FPGA. Was as simple as changing the input clock to get PLL2 used, and SDRAM is now behaving nicely at 100MHz. It has a footprint for SRAM which of course is much easier to use so I'll have a dig around to see if I can find one with the right package, after all the goal is to have a reasonably small core that can be ported to much smaller/cheaper FPGA's. Most of this so far hasnt' been about driving the display, its been sorting out the SDRAM controller to do burst reads for a FIFO :/