Jump to content
  • 0

SPI TFT Display


Riesenrad

Question

Hello everybody.

I recently got this SPI TFT display for my Raspberry Pi: 

https://www.conrad.at/de/raspberry-pi-display-modul-schwarz-rb-tft32-v2-raspberry-pi-a-b-b-raspberry-pi-1380381.html

http://joy-it.net/tft-display-3-2-v2/

But I'd have more use for it in an FPGA project of mine.

Now, I couldn't really find a pinout but as it's made for Raspberry Pi I could already figure out what lines are already reserved for power and with a little bit of luck, the MOSI / MISO / SCLK / Chip Select run on these pins: https://de.pinout.xyz/pinout/pitft_plus_35

I just wanted to know whether anyone has done this already and / or knows the pinout. Also, what could happen if I put data / voltage on the "wrong" pins?

Also, is there something like an IP block that you can use for this type of stuff or would I need to write everything by myself?

Thank you in advance! I've never used a display (except VGA) with my board so that's why I ask all these questions.... 

Link to comment
Share on other sites

23 answers to this question

Recommended Posts

2 hours ago, xc6lx45 said:

You can try this one, attached. It's about as basic as it gets. There is default content in the screen buffer => just wire it up and you should see some weird picture.
 

The character mem and display buffer use the same memory. This was really designed for minimum size on a Spartan 6 (1 block RAM and a bunch of LUTs). I can pack, I think, about fourty of them on one chip...

it needs a 21.75 MHz pixel clock (clk)  for 640x480@60 Hz for the graphics card end (only, the memory bus side allows its own, independent clock).

This is the interface:

module sk61_VGA(clk, clkConfig, in_we, in_addr, in_data, out_data, out_vsync, out_hsync, out_blank, out_rgb);

clkConfig, in_we, in_addr, in_data, out_data: That's the bus where you write into the screenbuffer or modify the character RAM (can even do small graphics...)

out_vsync, out_hsync, out_blank, out_rgb This goes to the monitor, ignore "blank". For total late-70ies look-and-feel use monochrome green and leave R&B open :-)

sk61_VGA.v

Cool thanks!
I'll try to make it work ?

So basically I connect a 21.75MHz clock (divide the 100MHz clock from my board by 5), and connect the out_vsync and out_hsync to the corresponding VGA pins that are also on my board, and connect nothing to out_blank? What do I connect out_rgb to?

Link to comment
Share on other sites

In the meantime I've turned the VGA adapter into an AXI-LITE slave, attached.

E.g. put it as RTL module into a ZYNQ design.
Autoconnect will then add an "interconnect" to convert between AXI and AXI-Lite.

Use a clock wizard (MMCM mode works best) to proved the 25.175 MHz VGA clock. The bus clock does not matter.

It's tested for basic functionality.

For example, this...

int main()
{
    init_platform();
volatile char* p = (char*)(0x40000000+848);
for (int ix = 0; ix < 20; ++ix){
	*p = *p ^ 0x80;
	++p;
}
...
                         

... for a base address of 0x40000000 inverts the first 20 characters by setting bit 7 (run it twice without reloading the bitstream => back to original).

vga.v

Link to comment
Share on other sites

1 hour ago, xc6lx45 said:

Yes exactly. On a rising clock edge (and I never care about the falling ones :-) ) the memory will load the given value into the given memory slot if WE is high. Otherwise, it'll read the memory contents.

The code is supposed to write 65d, 66, 76, 68... (ABCDEF...) into address 880d, 881, 882, 883 and it stops after a while....The two +1 increase the address and the data for every clock.
I have subtracted one from the initial values just as a reminder that it gets increased already for the first write event. So the initial value is 64, but for the first write this becomes 65 => "A".

Writing more than one byte, sorry, no (it is possible - anything is possible. But not in a way that would simplify things...).

One solution is to write a little state machine that prints a 32-bit hex number and a space.

Thanks, I managed to have it display 3 words in a loop with 1 second delay. It wasn't very difficult :-) 
I uncommented the mem[....] lines after the address 848 to have an empty screen apart from my text and it works great!

Link to comment
Share on other sites

Yes exactly. On a rising clock edge (and I never care about the falling ones :-) ) the memory will load the given value into the given memory slot if WE is high. Otherwise, it'll read the memory contents.

The code is supposed to write 65d, 66, 76, 68... (ABCDEF...) into address 880d, 881, 882, 883 and it stops after a while....The two +1 increase the address and the data for every clock.
I have subtracted one from the initial values just as a reminder that it gets increased already for the first write event. So the initial value is 64, but for the first write this becomes 65 => "A".

Writing more than one byte, sorry, no (it is possible - anything is possible. But not in a way that would simplify things...).

One solution is to write a little state machine that prints a 32-bit hex number and a space.

Link to comment
Share on other sites

4 hours ago, xc6lx45 said:

Congratulations. That was the hard part...

Study the schematic of your board around the VGA connector. There will most likely be several "bits" for each red/green/blue that are combined with resistors. Looks like you picked the lowest bit (with the highest resistor). This can be used to change the brightness level of each channel.

For a quick-and-dirty write test, try this (didn't build it myself)

   // note: define those regs before using them for the first time
   reg [10:0]            myAddr = 848-1; // screen base address
   reg [7:0]            myData = 65-1; "A"
   reg                myWriteEnable = 1'b0;
   always @(posedge anyClockYouLikeVgaClkWillDoToo) begin
      if (myAddr < 11'd880) begin
    
     myAddr <= myAddr + 11'd1;
     myWriteEnable <= 1'b1;
     myData <= myData + 8'd1;
    
      end else begin    
     myWriteEnable <= 1'b0;
      end
   end

...

sk61_VGA myGraphicsCardInstance(... .clkConfig(anyClockYouLikeVgaClkWillDoToo), .in_we(myWriteEnable), .in_addr(myAddr), .in_data(myData), .out_data( ... leave this open, until you want to read from mem ...), ...);

 

 

Great!

Oh I see, so that's why for R, G, and B there are 4 Bit Signals! Yes, I picked the lowest bit.

Thank you very much for the code example. So I'd put data into the myData register and pull myWriteEnable high when I want to add that letter (e.g.) to the data array?

Can I write more than 1 byte per clock cycle at once (using e.g. a 128 bit myData register) using your code? And why has a '1' to be added to the data?

Sorry for all those questions.. :rolleyes:

Link to comment
Share on other sites

Congratulations. That was the hard part...

Study the schematic of your board around the VGA connector. There will most likely be several "bits" for each red/green/blue that are combined with resistors. Looks like you picked the lowest bit (with the highest resistor). This can be used to change the brightness level of each channel.

For a quick-and-dirty write test, try this (didn't build it myself)

   // note: define those regs before using them for the first time
   reg [10:0]            myAddr = 848-1; // screen base address
   reg [7:0]            myData = 65-1; "A"
   reg                myWriteEnable = 1'b0;
   always @(posedge anyClockYouLikeVgaClkWillDoToo) begin
      if (myAddr < 11'd880) begin
    
     myAddr <= myAddr + 11'd1;
     myWriteEnable <= 1'b1;
     myData <= myData + 8'd1;
    
      end else begin    
     myWriteEnable <= 1'b0;
      end
   end

...

sk61_VGA myGraphicsCardInstance(... .clkConfig(anyClockYouLikeVgaClkWillDoToo), .in_we(myWriteEnable), .in_addr(myAddr), .in_data(myData), .out_data( ... leave this open, until you want to read from mem ...), ...);

 

 

Link to comment
Share on other sites

4 hours ago, xc6lx45 said:

yeps... hate to admit it but it's just a monochrome VGA adapter :-)
As long as you hook it up to at least one of the red/green/blue channels, it should show something. You can then combine to any color you like (e.g. red+green => yellow).

It wouldn't be too hard to add some color dispatching (e.g. use the high bit I'm using for reversed characters to switch between red and green). It's an FPGA, complete freedom (and never enough RAM...)

Hello, 
Very nice - your code worked and it displayed a part of "lorem ipsum"!

Now, I have 2 questions:

1) The text was extremely dim. I could barely see it - viewing the screen from the side was a lot better so I could definitely tell *what* was displayed but it just wasn't bright at all. What might this issue be related to? For the clock, I first created a 21.75 MHZ one with the IP but the screen didn't like it, then I found a table somewhere on the internet that had something with 25.X, used that, worked. Maybe just still not quite there with the clock?

2) How can I have it display my own text? From what I understand, it gets the data from memory. How would I store the data in memory and where? (Not in the code but at runtime)

Thank you in advance!

Link to comment
Share on other sites

20 minutes ago, xc6lx45 said:

yeps... hate to admit it but it's just a monochrome VGA adapter :-)
As long as you hook it up to at least one of the red/green/blue channels, it should show something. You can then combine to any color you like (e.g. red+green => yellow).

It wouldn't be too hard to add some color dispatching (e.g. use the high bit I'm using for reversed characters to switch between red and green). It's an FPGA, complete freedom (and never enough RAM...)

Oh I see, dude that's totally fine for me thank you again! :-)
I'll try it later. I assume all combined → white?

That's true ;-) But I only need to display a few numbers anyway. And the Nexys 4 DDR has decent RAM imho.

Link to comment
Share on other sites

yeps... hate to admit it but it's just a monochrome VGA adapter :-)
As long as you hook it up to at least one of the red/green/blue channels, it should show something. You can then combine to any color you like (e.g. red+green => yellow).

It wouldn't be too hard to add some color dispatching (e.g. use the high bit I'm using for reversed characters to switch between red and green). It's an FPGA, complete freedom (and never enough RAM...)

Link to comment
Share on other sites

7 minutes ago, xc6lx45 said:

Yes, but VGA is pretty sensitive to timing. 20 MHz will probably not be accepted by the monitor. Use the clocking wizard to create a PLL with input frequency 100M, output freq 21.75 M (e.g. 21.85M actual was OK when I tried). It takes some time to get it sorted out once, but then it only takes a few mouse clicks. There should be an instantiation template in the generated files for copy and paste.

Out_rgb goes to the red / green / blue channels of the monitor. If in doubt, connect to all three => white font. You may have a resistive DAC on your board with for example three outputs for each. Simply connect them all together.

Okay, I'll try that wizard, then! Thanks for the hint. In one of my previous trials using VGA, the monitor kept showing an error. I think that was it ;)

But Out_rgb is a single signal, isn't it?

Link to comment
Share on other sites

Yes, but VGA is pretty sensitive to timing. 20 MHz will probably not be accepted by the monitor. Use the clocking wizard to create a PLL with input frequency 100M, output freq 21.75 M (e.g. 21.85M actual was OK when I tried). It takes some time to get it sorted out once, but then it only takes a few mouse clicks. There should be an instantiation template in the generated files for copy and paste.

Out_rgb goes to the red / green / blue channels of the monitor. If in doubt, connect to all three => white font. You may have a resistive DAC on your board with for example three outputs for each. Simply connect them all together.

Link to comment
Share on other sites

3 hours ago, Riesenrad said:

Thank you anyways ;-)

My first tests weren't too successful though, so if you got some nice resources, I'd be happy to read them!

The physical connection part isn't an issue as my board has a VGA connector. It's more about "how to put that data into the blockram you mentioned, how to display it,.."

Thanks in advance!

You can try this one, attached. It's about as basic as it gets. There is default content in the screen buffer => just wire it up and you should see some weird picture.
 

The character mem and display buffer use the same memory. This was really designed for minimum size on a Spartan 6 (1 block RAM and a bunch of LUTs). I can pack, I think, about fourty of them on one chip...

it needs a 21.75 MHz pixel clock (clk)  for 640x480@60 Hz for the graphics card end (only, the memory bus side allows its own, independent clock).

This is the interface:

module sk61_VGA(clk, clkConfig, in_we, in_addr, in_data, out_data, out_vsync, out_hsync, out_blank, out_rgb);

clkConfig, in_we, in_addr, in_data, out_data: That's the bus where you write into the screenbuffer or modify the character RAM (can even do small graphics...)

out_vsync, out_hsync, out_blank, out_rgb This goes to the monitor, ignore "blank". For total late-70ies look-and-feel use monochrome green and leave R&B open :-)

sk61_VGA.v

Link to comment
Share on other sites

On 1/31/2018 at 6:33 PM, JColvin said:

Hi @Riesenrad,

The IP Cores for both the Pmod OLED and the Pmod OLEDrgb are free for download and use on our GitHub here and here. You can write your own your own controller for it, but there is quite the initialization sequence associated with it (illustrated on Pmod OLEDrgb here) so it might not be ideal to recreate yourself.

Thanks,
JColvin

They are only for designs that include a MicoBlaze?
My circuit is logic only.... I don't want to add a MicroBlaze just for the display output.

Link to comment
Share on other sites

On 1/30/2018 at 4:30 PM, xc6lx45 said:

Right... sorry, didn't read the last line of your original post.

Thank you anyways ;-)

My first tests weren't too successful though, so if you got some nice resources, I'd be happy to read them!

The physical connection part isn't an issue as my board has a VGA connector. It's more about "how to put that data into the blockram you mentioned, how to display it,.."

Thanks in advance!

Link to comment
Share on other sites

Hi @Riesenrad,

The IP Cores for both the Pmod OLED and the Pmod OLEDrgb are free for download and use on our GitHub here and here. You can write your own your own controller for it, but there is quite the initialization sequence associated with it (illustrated on Pmod OLEDrgb here) so it might not be ideal to recreate yourself.

Thanks,
JColvin

Link to comment
Share on other sites

1 hour ago, xc6lx45 said:

Hi,

one option - depending on your needs - is to simply hook up a regular VGA monitor via the RGB cable. Actually, jumper cables with female ends can be plugged right into to a 15-pin sub-D connector. A 40x20 monochrome text display fits into the smallest block RAM, needs three pins (HSYNC, VSYNC and e.g. GREEN) and looks very much like 1979...

How do you mean "via RGB cable"?
You mean using the regular VGA connector that is on the board?

Link to comment
Share on other sites

3 hours ago, JColvin said:

Hi @Riesenrad,

This is definitely a biased answer, but we do have the Pmod MTDS, which is a 2.8" touchscreen with code available on our GitHub. The Pmod OLED and Pmod OLEDrgb also work nicely with FPGAs, but as you note they aren't the largest screens available.

Let me know if you have any other questions.

Thanks,
JColvin

Yeah, but it is a bit too expensive for me ;)

How would one use the Pmod OLED / OLEDrgb? IP core or is it 100% open and you could do your own controller circuit?

Link to comment
Share on other sites

Hi,

one option - depending on your needs - is to simply hook up a regular VGA monitor via the RGB cable. Actually, jumper cables with female ends can be plugged right into to a 15-pin sub-D connector. A 40x20 monochrome text display fits into the smallest block RAM, needs three pins (HSYNC, VSYNC and e.g. GREEN) and looks very much like 1979...

Link to comment
Share on other sites

35 minutes ago, JColvin said:

Hi @Riesenrad,

I haven't worked with that particular display so I don't know the pinout of the TFT display. In terms of what could happen if you plugged in the data and voltage pins incorrectly, the general hope is that nothing goes terribly wrong aside from the display not displaying anything, but that depends on how the display was designed in hardware. Alternatively, the worse that could happen is that you short out one of the boards (either the FPGA or the display), potentially causing permanent damage, so you'll definitely want to make sure that the pins are going to the correct places.

Looking at their guide (link), it appears that they are expecting you to download their software to an SD card which is designed to interact with the Raspbian OS, so I doubt there is any IP core developed for the board so you would need to do a lot of development work to get that working, especially if you don't have access to the source code that is used to run the display.

Thanks,
JColvin

Hello JColvin,

Thank you very much for your answer!

Do you recommend an other, better documented LCD? I might return this thing and get another one, maybe.

What about the OLED Pmod? It’s a bit small but well documented afaik....

Thank you in advance!

dave

Link to comment
Share on other sites

Hi @Riesenrad,

I haven't worked with that particular display so I don't know the pinout of the TFT display. In terms of what could happen if you plugged in the data and voltage pins incorrectly, the general hope is that nothing goes terribly wrong aside from the display not displaying anything, but that depends on how the display was designed in hardware. Alternatively, the worse that could happen is that you short out one of the boards (either the FPGA or the display), potentially causing permanent damage, so you'll definitely want to make sure that the pins are going to the correct places.

Looking at their guide (link), it appears that they are expecting you to download their software to an SD card which is designed to interact with the Raspbian OS, so I doubt there is any IP core developed for the board so you would need to do a lot of development work to get that working, especially if you don't have access to the source code that is used to run the display.

Thanks,
JColvin

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...