Electronics > FPGA
LCD controller on FLGA. Altera.
Buriedcode:
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.
Buriedcode:
Well, since my question in my first post was both vague and overly 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;
wire outupdate;
wire halfway_pipe;
wire pix_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)
begin
state_count <= state_count +1;
if (outupdate)
pxlclkout <= 1;
else if (halfway_pulse)
pxlclkout <= 0;
end
always @(posedge clk)
begin
if (outupdate)
begin
if(CounterXmaxed)
CounterX <= 0;
else
CounterX <= CounterX + 1;
end
end
always @(posedge clk)
begin
if (outupdate)
begin
if(CounterXmaxed)
begin
if(CounterYmaxed)
CounterY <= 0;
else
CounterY <= CounterY + 1;
end
end
end
--- End code ---
'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!
Buriedcode:
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. :palm:
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.
AndyC_772:
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?
Buriedcode:
--- Quote from: AndyC_772 on June 30, 2016, 01:30:53 pm ---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?
--- End quote ---
Ultimately 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 interface :) I'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.
Navigation
[0] Message Index
[#] Next page
Go to full version