// --------------------------------------------------------------------
// Copyright (c) 2005 by Terasic Technologies Inc. 
// --------------------------------------------------------------------
//
// Permission:
//
//   Terasic grants permission to use and modify this code for use
//   in synthesis for all Terasic Development Boards and Altera Development 
//   Kits made by Terasic.  Other use of this code, including the selling 
//   ,duplication, or modification of any portion is strictly prohibited.
//
// Disclaimer:
//
//   This VHDL/Verilog or C/C++ source code is intended as a design reference
//   which illustrates how these types of functions can be implemented.
//   It is the user's responsibility to verify their design for
//   consistency and functionality through the use of formal
//   verification methods.  Terasic provides no warranty regarding the use 
//   or functionality of this code.
//
// --------------------------------------------------------------------
//           
//                     Terasic Technologies Inc
//                     356 Fu-Shin E. Rd Sec. 1. JhuBei City,
//                     HsinChu County, Taiwan
//                     302
//
//                     web: http://www.terasic.com/
//                     email: support@terasic.com
//
// --------------------------------------------------------------------
//
// Major Functions:	This funtion will config and read Touch Screen Digitizer 
// 					X an Y coordinate form LTM 
// --------------------------------------------------------------------
//
// Revision History :
// --------------------------------------------------------------------
//   Ver  :| Author            :| Mod. Date :| Changes Made:
//   V1.0 :| Johnny Fan        :| 06/03/23  :|      Initial Revision
// --------------------------------------------------------------------
module adc_spi_controller	(
					iCLK,
					iRST_n,
					oADC_DIN,
					oADC_DCLK,
					oADC_CS,
					iADC_DOUT,
					iADC_BUSY,
					iADC_PENIRQ_n,
					oX_COORD,
					oY_COORD,
					oNEW_COORD,

					);
					
//============================================================================
// PARAMETER declarations
//============================================================================	
parameter SYSCLK_FRQ	= 50000000;
parameter ADC_DCLK_FRQ	= 1000;
parameter ADC_DCLK_CNT	= SYSCLK_FRQ/(ADC_DCLK_FRQ*2);
					
//===========================================================================
// PORT declarations
//=========================================================================== 
input			iCLK;
input			iRST_n;
input			iADC_DOUT;
input			iADC_PENIRQ_n;
input			iADC_BUSY;
output			oADC_DIN;
output			oADC_DCLK;
output			oADC_CS;
output	[11:0]	oX_COORD;
output	[11:0]	oY_COORD;
output			oNEW_COORD;					
//=============================================================================
// REG/WIRE declarations
//=============================================================================
reg				d1_PENIRQ_n;
reg				d2_PENIRQ_n;
wire			touch_irq;
reg		[15:0]	dclk_cnt;
wire			dclk;
reg				transmit_en;
reg		[6:0]	spi_ctrl_cnt;
wire			oADC_CS;
reg				mcs;
reg				mdclk;
wire	[7:0]	x_config_reg;
wire	[7:0]	y_config_reg;
wire	[7:0]	ctrl_reg;
reg		[7:0]	mdata_in;
reg				y_coordinate_config;
wire			eof_transmition;	
reg		[5:0]	bit_cnt;	
reg				madc_out;	
reg		[11:0]	mx_coordinate;
reg		[11:0]	my_coordinate;	
reg		[11:0]	oX_COORD;
reg		[11:0]	oY_COORD;
wire			rd_coord_strob;
reg				oNEW_COORD;
reg		[5:0]	irq_cnt;
reg		[15:0]	clk_cnt;
//=============================================================================
// Structural coding
//=============================================================================
assign	x_config_reg = 8'h92;
assign	y_config_reg = 8'hd2;

always@(posedge iCLK or negedge iRST_n)
	begin
		if (!iRST_n)
			madc_out <= 0;
		else
			madc_out <= iADC_DOUT;
	end		

///////////////   pen irq detect  //////// 
always@(posedge iCLK or negedge iRST_n)
	begin	
		if (!iRST_n)
			begin
				d1_PENIRQ_n	<= 0;
				d2_PENIRQ_n	<= 0;
			end
		else
			begin
				d1_PENIRQ_n	<= iADC_PENIRQ_n;	
				d2_PENIRQ_n	<= d1_PENIRQ_n;
			end
	end

// if iADC_PENIRQ_n form high to low , touch_irq goes high
assign		touch_irq = d2_PENIRQ_n & ~d1_PENIRQ_n; 

// if touch_irq goes high , starting transmit procedure ,transmit_en goes high
// if end of transmition and no penirq , transmit procedure stop.

always@(posedge iCLK or negedge iRST_n)
	begin
		if (!iRST_n)
			transmit_en <= 0;
		else if (eof_transmition&&iADC_PENIRQ_n) 
			transmit_en <= 0;	
		else if (touch_irq)
			transmit_en <= 1;
	end			

always@(posedge iCLK or negedge iRST_n)
	begin
		if (!iRST_n)
			dclk_cnt <= 0;
		else if (transmit_en) 
			begin
				if (dclk_cnt == ADC_DCLK_CNT)
					dclk_cnt <= 0;
				else
					dclk_cnt <= dclk_cnt + 1;		
			end
		else
			dclk_cnt <= 0;
	end			
	
assign	dclk =   (dclk_cnt == ADC_DCLK_CNT)? 1 : 0;		

always@(posedge iCLK or negedge iRST_n)
	begin
		if (!iRST_n)
			spi_ctrl_cnt <= 0;
		else if (dclk)	
			begin
				if (spi_ctrl_cnt == 49)
					spi_ctrl_cnt <= 0;						
				else
					spi_ctrl_cnt <= spi_ctrl_cnt + 1;		
			end
	end				

always@(posedge iCLK or negedge iRST_n)
	begin
		if (!iRST_n)
			begin
				mcs 	<= 1;
				mdclk	<= 0;
				mdata_in <= 0;
				y_coordinate_config <= 0;
				mx_coordinate <= 0;
				my_coordinate <= 0;
			end
		else if (transmit_en)
			begin
				if (dclk)
					begin
						if (spi_ctrl_cnt == 0)
							begin
								mcs 	<= 0;
								mdata_in <= ctrl_reg;
							end	
						else if (spi_ctrl_cnt == 49)
							begin
								mdclk	<= 0;
								y_coordinate_config <= ~y_coordinate_config;
								
								if (y_coordinate_config)
									mcs 	<= 1;
								else
									mcs 	<= 0;	
							end
						else if (spi_ctrl_cnt != 0)
							mdclk	<= ~mdclk;				
						if (mdclk)
							mdata_in <= {mdata_in[6:0],1'b0};
						if (!mdclk)	
							begin
								if(rd_coord_strob)
									begin
										if(y_coordinate_config)
											my_coordinate <= {my_coordinate[10:0],madc_out};
										else
											mx_coordinate <= {mx_coordinate[10:0],madc_out};	
									end
							end		
					end				
			end
	end

assign	oADC_CS  = mcs;
assign	oADC_DIN = 	mdata_in[7];
assign	oADC_DCLK = mdclk;
assign	ctrl_reg = y_coordinate_config ? y_config_reg : x_config_reg;
 
assign	eof_transmition = (y_coordinate_config & (spi_ctrl_cnt == 49) & dclk);

assign	rd_coord_strob = ((spi_ctrl_cnt>=19)&&(spi_ctrl_cnt<=41)) ? 1 : 0;

always@(posedge iCLK or negedge iRST_n)
	begin
		if (!iRST_n)
			begin
				oX_COORD <= 0;	
				oY_COORD <= 0;
			end
		else if (eof_transmition&&(my_coordinate!=0))
			begin			
				oX_COORD <= mx_coordinate;	
				oY_COORD <= my_coordinate;
			end	
	end

always@(posedge iCLK or negedge iRST_n)
	begin
		if (!iRST_n)
			oNEW_COORD <= 0;
		else if (eof_transmition&&(my_coordinate!=0))
			oNEW_COORD <= 1;
		else
			oNEW_COORD <= 0;		
	end

endmodule