Programmable Devices
CPLDs, FPGAs, SoC FPGAs, Configuration, and Transceivers
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
21615 Discussions

VHDL ili9341 configuration

Manzy
Beginner
611 Views

Manzy_0-1739430071616.png

this is the lcd ili9341 screen im trying to configure with VHDL for project, ill add here in the end the modules i built. i created an SPI module and ili configuration module by looking at the data sheet and inspecting another modules online, i find it dificult to configure it with the configurations i have found, also i have tried to work with lower system clk for the SCK around 10MHZ so the system would not exeed the system clock that should be maximum 24MHZ. please someone could help me find a way to configure it and explain to me the process of showing data over the screen.

 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
 
entity ili9341_spi is
    Port ( 
        spiClk        : in     std_logic;                    -- Input clock signal for SPI timing 12Mhz
        data          : in     std_logic_vector(8 downto 0); -- 9-bit data to be transmitted (MSB is DC flag)
        dataAvailable : in     std_logic;                    -- Indicates that new data is available for transmission
        tft_sck       : out    std_logic;                    -- SPI clock output to the TFT (active only when CS is active)
        tft_sdi       : out    std_logic;                    -- SPI data output to the TFT (serial data line)
        tft_dc        : out    std_logic;                    -- Data/Command (DC) signal for the TFT (MSB of the data)
        tft_cs        : out    std_logic;                    -- Chip Select (CS) signal for the TFT (active low)
        idle          : buffer std_logic := '1'              -- Indicates the SPI module is idle (1 when no transmission in progress)
);
end ili9341_spi;
 
architecture ili9341_spi_arc of ili9341_spi is
-- Registers
signal send_index     : integer range 1 to 7 := 1;
    signal internalData   : std_logic_vector(8 downto 0) := (others => '0');
signal cs             : std_logic := '1';
 
    -- Combinational Assignments / wires
    signal dataDc         : std_logic;
    signal dataShift      : std_logic_vector(0 to 7);
 
begin
 
-- Wires Assignments
    dataDc    <= internalData(8);
    dataShift <= internalData(7 downto 0);
 
-- SPI transmit
process(spiClk)
begin
if rising_edge(spiClk) then
-- Store new data in internal register
-- Having Data and ready to transmite
            if dataAvailable = '1' and idle = '1' then
                internalData <= data; -- Copy new data into internal buffer
                idle      <= '0';  -- Start transmission
cs <= '0';  -- ili9341 selected
tft_sdi      <= dataShift(0);
            --end if;
 
-- Change data if we're actively sending
            elsif idle = '0' then
-- Update Pins
tft_sdi <= dataShift(send_index);
 
-- Increment counter
if send_index = 7 then 
send_index <= 1;    -- Reset send_index after sending 8bits
idle       <= '1';  -- sending last bit;
else
send_index <= send_index + 1;
end if;
 
-- no data to send
else 
cs <= '1';
end if;
end if;
end process;
 
    -- Assigning
tft_dc  <= dataDc;
    tft_sck <= spiClk and not cs;  -- only drive sck with an active CS
tft_cs  <= cs;
 
end ili9341_spi_arc;

 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use work.ili9341_pkg.all;
 
entity ili9341 is
    Port (
        clk             : in  std_logic;                      -- Input clock (e.g., 100MHz)
        tft_sck         : out std_logic;                      -- SPI clock signal
        tft_sdi         : out std_logic;                      -- SPI data output (MOSI)
        tft_dc          : out std_logic;                      -- Data/Command signal
        tft_reset       : out std_logic;                      -- Reset signal for the TFT (active low)
        tft_cs          : out std_logic;                      -- Chip Select (active low)
     --   framebufferData : in  std_logic_vector(15 downto 0):=x"00";  -- RGB565 data input for the frame buffer
led     : out std_logic_vector(3 downto 0);
        framebufferClk  : out std_logic                       -- Framebuffer clock to synchronize data reading
    );
end ili9341;
 
architecture ili9341_arc of ili9341 is
 
-- Constant
constant INPUT_CLK_MHZ : integer := 24;
 
-- Signals
signal spiClk : std_logic := '0';       -- Generated 10-12MHz clk
signal spi_counter_clk  : integer range 0 to 10 := 0;     -- Counter For spiClk
 
signal frameBufferLowNibble : std_logic := '1';        
 
    signal spiData        : std_logic_vector(8 downto 0) := (others => '0'); -- Data to send via SPI
    signal spiDataSet      : std_logic := '0';               -- Indicates new data is ready
signal spiIdle        : std_logic := '1';               -- Indicates SPI is idle
 
component ili9341_spi
    Port ( 
        spiClk        : in     std_logic;                    -- Input clock signal for SPI timing 12Mhz
        data          : in     std_logic_vector(8 downto 0); -- 9-bit data to be transmitted (MSB is DC flag)
        dataAvailable : in     std_logic;                    -- Indicates that new data is available for transmission
        tft_sck       : out    std_logic;                    -- SPI clock output to the TFT (active only when CS is active)
        tft_sdi       : out    std_logic;                    -- SPI data output to the TFT (serial data line)
        tft_dc        : out    std_logic;                    -- Data/Command (DC) signal for the TFT (MSB of the data)
        tft_cs        : out    std_logic;                    -- Chip Select (CS) signal for the TFT (active low)
        idle          : buffer std_logic := '1'              -- Indicates the SPI module is idle (1 when no transmission in progress)
);
end component;
 
-- state machine with delay + idle support (used for initialization)
    signal remainingDelayTicks  : integer := 0;
type state_type is ( START, HOLD_RESET, WAIT_FOR_POWERUP, SEND_INIT_SEQ, END_LOOP);
signal state : state_type := START;
 
signal framebufferDataS : std_logic_vector(15 downto 0) := x"F800";
 
signal initSeqCounter       : integer range 0 to INIT_SEQ_LEN := 0;
 
begin
 
-- SPI_ILI9341 Unit
ili9341_Unit : ili9341_spi
port map (
            spiClk        => spiClk,
            data          => spiData,
            dataAvailable => spiDataSet,
            tft_sck       => tft_sck,
            tft_sdi       => tft_sdi,
            tft_dc        => tft_dc,
            tft_cs        => tft_cs,
            idle          => spiIdle
);
 
spiClk_process : 
process (clk)
begin
if rising_edge(clk) then
if spi_counter_clk = 10 then
spiClk <= not spiClk;
spi_counter_clk <= 0;
else
spi_counter_clk <= spi_counter_clk + 1;
end if;
end if;
end process;
 
process (spiClk) 
begin
if rising_edge(spiClk) then
-- clear data flag first
spiDataSet <= '0';
 
-- always decrement delay ticks
if remainingDelayTicks > 0 then
remainingDelayTicks <= remainingDelayTicks - 1;
 
elsif (spiIdle and not spiDataSet) = '1' then
-- advance state machine to next state, but only do this if we
-- didn't just clock in the last byte (since idle is not yet updated)
case state is
-- initialize all pins in START mode; reset the LCD
when START =>
led <= "0001";
tft_reset <= '0';
remainingDelayTicks <= INPUT_CLK_MHZ * 100;
state         <= HOLD_RESET;
 
-- wait for RESET to kick in; then release pin & wait for power up
when HOLD_RESET =>
led <= "0010";
tft_reset     <= '1'; -- release pin
remainingDelayTicks <= INPUT_CLK_MHZ * 12000;
state     <= WAIT_FOR_POWERUP;
 
-- if power up is completed -> sw reset
when WAIT_FOR_POWERUP =>
led <= "0100";
spiData        <= COM & x"11";
spiDataSet <= '1';
remainingDelayTicks <= INPUT_CLK_MHZ * 5000;
state <= SEND_INIT_SEQ;
 
when SEND_INIT_SEQ => 
led <= "1000";
if initSeqCounter < INIT_SEQ_LEN  then
spiData       <= INIT_SEQ(initSeqCounter);
spiDataSet    <= '1';
remainingDelayTicks <= 6000000;
initSeqCounter <= initSeqCounter + 1;
else
state     <= END_LOOP;
end if;
 
when END_LOOP =>
led <= "1111";
if frameBufferLowNibble = '0' then
--spiData <= ('1' & framebufferData(15 downto 8));
spiData <= ('1' & framebufferDataS(15 downto 8));
else
--spiData <= ('1' & framebufferData(7 downto 0));
spiData <= ('1' & framebufferDataS(7 downto 0));
end if;
spiDataSet <= '1';
frameBufferLowNibble <= not frameBufferLowNibble;
end case;
 
end if;
 
end if;
end process;
 
-- Assigns
framebufferClk <= not frameBufferLowNibble;
 
end ili9341_arc;
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
package ili9341_pkg is
 
constant COM : std_logic := '0'; -- Command
constant DAT : std_logic := '1'; -- Data
 
constant INIT_SEQ_LEN : integer := 52;
type init_seq_array is 
--array (natural range <>) of std_logic_vector(8 downto 0);
array (0 to INIT_SEQ_LEN-1) of std_logic_vector(8 downto 0);
 
constant INIT_SEQ : init_seq_array := (
-- Turn off Display
(COM & x"28"),
-- Init (??)
(COM &  x"CF"), (DAT &  x"00"), (DAT &  x"83"), (DAT &  x"30"), 
    (COM &  x"ED"), (DAT &  x"64"), (DAT &  x"03"), (DAT &  x"12"), (DAT &  x"81"),
(COM &  x"E8"), (DAT &  x"85"), (DAT &  x"01"), (DAT &  x"79"), 
(COM &  x"CB"), (DAT &  x"39"), (DAT &  x"2C"), (DAT &  x"00"), (DAT &  x"34"), (DAT &  x"02"),
(COM &  x"F7"), (DAT &  x"20"),
(COM &  x"EA"), (DAT &  x"00"), (DAT &  x"00"),
-- Power Control
(COM & x"C0"), (DAT & x"26"),
(COM & x"C1"), (DAT & x"11"),
--VCOM
(COM & x"C5"), (DAT & x"35"), (DAT & x"3E"),
(COM & x"C7"), (DAT & x"BE"),
-- Memory Access Control
(COM & x"3A"), (DAT & x"55"),
-- Frame Rate
(COM & x"B1"), (DAT & x"00"), (DAT & x"1B"),
-- Gamma
(COM & x"26"), (DAT & x"01"),
-- Brightness
(COM & x"51"), (DAT & x"FF"),
-- Display
(COM & x"B7"), (DAT & x"07"),
(COM & x"B6"), (DAT & x"0A"), (DAT & x"82"), (DAT & x"27"), (DAT & x"00"),
(COM & x"29"), -- Enable Display
(COM & x"2C") -- Start  Memory-Write
);
 
 
end package ili9341_pkg;
 

 

 

Labels (1)
0 Kudos
2 Replies
ShengN_Intel
Employee
506 Views

Hi,


Is this module from other vendor? If yes, I think you need to get the design example from that vendor.


Thanks,

Regards,

Sheng


0 Kudos
FvM
Honored Contributor II
488 Views
Hi,
I won't expect that someone is willing to review your code unless they are already involved with ili9341. Most driver solutions are uC based, I noticed however a Verilog ili9341 driver project at Github. I'd start from there.
0 Kudos
Reply