Programmable Devices
CPLDs, FPGAs, SoC FPGAs, Configuration, and Transceivers
20764 Discussions

Problems using a Dual access on-chip memory module (QSYS)

MartBent
Novice
1,057 Views

Hello,

 

I have a QSYS system using a Nios II/e processor along with some vhdl modules which should be able to display pixels on a LCD display using a VGA controller. I have already managed to get the Nios II code working as well as the VGA interface. 

I now seek to access the memory set by the Nios II code in VHDL to retrieve the pixel data and pass them onto the VGA interface, this should be possible with the dual access memory module in QSYS.

This is the toplevel VHDL code:

LIBRARY ieee;
USE ieee.std_logic_1164.all;
use ieee.numeric_std.all;

ENTITY niosdisplay IS
	PORT(
		clk			:  IN  	STD_LOGIC;
		key			:  IN 	STD_LOGIC;
		pixel_clk   :  OUT   STD_LOGIC;
		red			:	OUT	STD_LOGIC_VECTOR(7 DOWNTO 0) := (OTHERS => '1');  --red magnitude output to DAC
		green			:	OUT	STD_LOGIC_VECTOR(7 DOWNTO 0) := (OTHERS => '1');  --green magnitude output to DAC
		blue			:	OUT	STD_LOGIC_VECTOR(7 DOWNTO 0) := (OTHERS => '1'); --blue magnitude output to DAC
		btn			:	IN	STD_LOGIC_VECTOR(3 DOWNTO 0) := (OTHERS => '0'); --btn pio
		h_sync    	: OUT  STD_LOGIC;
		v_sync    	: OUT  STD_LOGIC;
		n_blank     : OUT  STD_LOGIC;
		n_sync  	  	: OUT  STD_LOGIC
		);
END niosdisplay;

ARCHITECTURE behavior OF niosdisplay IS
COMPONENT vga_controller IS
  PORT(
    pixel_clk : IN   STD_LOGIC;  --pixel clock at frequency of VGA mode being used
    reset_n   : IN   STD_LOGIC;  --active low asycnchronous reset
    h_sync    : OUT  STD_LOGIC;  --horiztonal sync pulse
    v_sync    : OUT  STD_LOGIC;  --vertical sync pulse
    disp_ena  : OUT  STD_LOGIC;  --display enable ('1' = display time, '0' = blanking time)
    column    : OUT  INTEGER;    --horizontal pixel coordinate
    row       : OUT  INTEGER;    --vertical pixel coordinate
    n_blank   : OUT  STD_LOGIC;  --direct blacking output to DAC
    n_sync    : OUT  STD_LOGIC --sync-on-green output to DAC
	 );
END COMPONENT vga_controller;
COMPONENT altpll0 IS
	PORT
	(
		areset		: IN STD_LOGIC  := '0';
		inclk0		: IN STD_LOGIC  := '0';
		c0				: OUT STD_LOGIC
	);
END COMPONENT altpll0;

COMPONENT system is
	port (
		btn_pio_export       : in  std_logic_vector(3 downto 0)  := (others => '0'); --   btn_pio.export
		clk_clk              : in  std_logic                     := '0';             --       clk.clk
		frame_buf_address    : in  std_logic_vector(16 downto 0) := (others => '0'); -- frame_buf.address
		frame_buf_chipselect : in  std_logic                     := '0';             --          .chipselect
		frame_buf_clken      : in  std_logic                     := '0';             --          .clken
		frame_buf_write      : in  std_logic                     := '0';             --          .write
		frame_buf_readdata   : out std_logic_vector(31 downto 0);                    --          .readdata
		frame_buf_writedata  : in  std_logic_vector(31 downto 0) := (others => '0'); --          .writedata
		frame_buf_byteenable : in  std_logic_vector(3 downto 0)  := (others => '0'); --          .byteenable
		reset_reset_n        : in  std_logic                     := '0'              --     reset.reset_n
	);
END COMPONENT system;

--VGA Stuff
signal clk_138 : std_logic;
signal column : integer;
signal row : integer;
signal disp_ena : std_logic;

--Nios II Stuff
signal mem_data : std_logic_vector(31 downto 0) := (others => '0');
signal frame_buf_addr : natural range 0 to 65536 := 0;

BEGIN
	
	u0: altpll0 port map('0', clk, clk_138);
	u1: vga_controller port map(clk_138, '1', h_sync,v_sync, disp_ena, column, row, n_blank, n_sync);
	u2: system port map(btn_pio_export => btn,
							  clk_clk => clk_138, 
							  reset_reset_n => '1', 
							  frame_buf_address => std_logic_vector(to_unsigned(frame_buf_addr, 17)), 
							  frame_buf_readdata => mem_data,
							  frame_buf_chipselect => '0'
							  );
	
	pixel_clk <= clk_138;
	
	draw_pixel : PROCESS(clk_138)
	
	variable count : natural range 0 to 4 := 0;
	
	BEGIN
	IF rising_edge(clk_138) then		
		IF disp_ena = '1' then
			--IF((row > 256) and (row < 256+512) and (column > 320) and (column < 320+512)) THEN --Inside game screen
				case count is
					when 0 =>
						red <= mem_data(31 downto 24);
						blue <= mem_data(31 downto 24);
						green <= mem_data(31 downto 24);
						count := 1;
					when 1 =>
						red <= mem_data(23 downto 16);
						green <= mem_data(23 downto 16);
						blue <= mem_data(23 downto 16);
						count := 2;
					when 2 =>
						red <= mem_data(15 downto 8);
						green <= mem_data(15 downto 8);
						blue <= mem_data(15 downto 8);
						count := 3;
						if(frame_buf_addr = 65535) then
						frame_buf_addr <= 0;
						else
							frame_buf_addr <= frame_buf_addr + 1;
						end if;
					when 3 =>
						red <= mem_data(7 downto 0);
						green <= mem_data(7 downto 0);
						blue <= mem_data(7 downto 0);
						count := 0;
					when others =>
						red <= mem_data(31 downto 24);
						green <= mem_data(31 downto 24);
						blue <= mem_data(31 downto 24);					
				end case;
			--ELSE --Gray color to boundary
				--red <= "11111001";
				--green <= "10101001";
				--blue <= "10101001";
			--END IF;
		ELSE					
			red <= (OTHERS => '0');
			green <= (OTHERS => '0');
			blue <= (OTHERS => '0');
		END IF;
	END IF;
	END PROCESS;
END behavior;

This is the Qsys system:

PD system.png

The code increments the address every 4 accesses so it sets a single byte every 4 clock cycles. But for some reason the readdata port of the memory module is not changed whenever the address changes. It seems to be stuck at address 0, this results in the screen having the same 4 pixel pattern throughout the screen. 

Here is a screenshot of a signal tap I did:

signal tap.png

 

As is visible in the picture, the frame_buffer_readdata does not change its data to the corresponding frame_buf_addr. I have tried playing with the byteenable and chipselect signals but nothing seems to work getting the module to respond to the address change. 

Does anyone have any idea what is wrong or what I am missing here?

 

Thanks,

Mart

0 Kudos
1 Solution
MartBent
Novice
884 Views

So I finally solved the issue...

The problem was that the frame_buffer address immediately changed back after 1 clock cycle. Since the memory has a delay it needs to be kept at their desired value for at least 2 clocks cycles, doing this will result in the readdata value changing in the third clock cycle. I have another post on reddit with a bit more context:

https://www.reddit.com/r/FPGA/comments/y1fkb1/problem_accessing_sdram_from_nios_iie_and_vhdl/

 

View solution in original post

0 Kudos
11 Replies
sstrell
Honored Contributor III
1,048 Views

Can you confirm the Nios is correctly writing data to the frame buffer?  If you don't have the correct data in the RAM, then the data you read won't be what you expect.

0 Kudos
MartBent
Novice
1,043 Views
Thanks for reply, I am able to set the memory using the FRAME_BUFFER_BASE constant in the nios header files. When I set it you can even see the pattern on the screen changing.
0 Kudos
uk49s
Beginner
1,036 Views

Read this discussion. May be this can help you here https://community.intel.com/t5/Intel-Quartus-Prime-Software/On-Chip-uk49s-Memory-in-Qsys-Quartus/td-p/126471. If yes then please mentioned me here.

0 Kudos
KellyJialin_Goh
Employee
993 Views

Hi,

I see that you managed to get the pixel pattern changing on your screen now, so may I know what is the current issue that you have?


Regards,

Kelly


0 Kudos
MartBent
Novice
988 Views

So, the pattern changes because I am setting the first byte of the memory (address 0). See this code snippet:

int main(void) {

	u8* addr = FRAME_BUFFER_BASE; //Starting point of the video buffer
	u8 color = 255;

	*(addr) = 0xFF;
	*(addr+1) = 0;
	*(addr+2) = 0;
	*(addr+3) = 0xFF;

	while(1){}
}

this SHOULD result in pixel 1 = WHITE, pixel 2 = BLACK pixel 3 = BLACK pixel 4 = WHITE. But whenever I try to read from another address in memory, the output does not change. Because it is not responding to the address change (in VHDL). See this signal tap:

signaltap.png

 

The frame_buf_addr changes but readdata field does not change into the next 32 bits.  Because it does not increment it just repeats the pattern of the first 4 pixels(32 bits) throughout the whole screen

screen1.jpeg

I want to cycle through the whole memory in VHDL so I can draw graphics like squares/circles.

 

Regards,

Mart

0 Kudos
sstrell
Honored Contributor III
977 Views

Hosts use byte addressing, so you should be increasing your address by 4 each time for a 32 bit data bus, but that doesn't explain the lack of change on readdata.  Hmm.

0 Kudos
KellyJialin_Goh
Employee
958 Views

Hi Mart,

I will get back to you on why it does not increment. Thank you.


Regards,

Kelly


0 Kudos
RichardTanSY_Intel
900 Views

Just to inform you that Kelly has hand over this case to me and I will looking into this.

Could you help to share your project .qar files so I can understand better on the design?

 

Best Regards,

Richard Tan

 

 

 

0 Kudos
MartBent
Novice
885 Views

So I finally solved the issue...

The problem was that the frame_buffer address immediately changed back after 1 clock cycle. Since the memory has a delay it needs to be kept at their desired value for at least 2 clocks cycles, doing this will result in the readdata value changing in the third clock cycle. I have another post on reddit with a bit more context:

https://www.reddit.com/r/FPGA/comments/y1fkb1/problem_accessing_sdram_from_nios_iie_and_vhdl/

 

0 Kudos
Joebiden
Beginner
859 Views

I now seek to access the memory set by the Nios II code in VHDL to retrieve the pixel data and pass them onto the VGA interface

0 Kudos
RichardTanSY_Intel
840 Views

Great to hear that. Sorry that I am not able to help out.


With that, I now transition this thread to community support. If you have a new question, Please login to ‘https://supporttickets.intel.com’, view details of the desire request, and post a feed/response within the next 15 days to allow me to continue to support you. After 15 days, this thread will be transitioned to community support. The community users will be able to help you on your follow-up questions.


Thank you.


Best Regards,

Richard Tan


p/s: If any answer from the community or Intel Support are helpful, please feel free to give best answer or rate 9/10 survey.



0 Kudos
Reply