Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Sync problem with SPI/Circuit interface code

Status
Not open for further replies.

sebmaster

Member level 1
Joined
Mar 9, 2008
Messages
38
Helped
2
Reputation
4
Reaction score
0
Trophy points
1,286
Activity points
1,719
Hello,

I have a very strange problem with my CPLD design.

In short, the excerpt below is designed to recieve a 22 bit word via SPI, then inform external logic it has recieved it. Only when the external logic signals that it has processed the word is the clear-to-send signal to be sent so the next one can be read in.

The problem is that sometimes it appears the word counter is incrementing too quickly or too slowly - if I look at it on the scope the CTS signal instead of changing at the end of the waveform will blip in the center between the rising edges of one SPI clock cycle. If I continue to send data it moves back and forth along the 22 cycles as if it was triggering too early and then being reset, or too late and it required another one or two cycles before the previous set was complete.

The 'jumping' doesnt happen all the time, it takes a few transmissions to throw it off, and when I first program the device it works fine for a while.

It isn't an off-by-one error with my VHDL as ive tested with both +/-1 on the threshold value and in both cases I could get consistent shifting of the CTS signal with respect to the waveform (left or right depending on whether the value was too small or too high).

Whats tricky about this is that the SPI clock is completely independant of the clock for the rest of the logic, hence the seperate process and 'propagate' signal to try and sync them.

I suspect it is something to do with the asynchronous clear resetting the counter somehow, or being high during an SPI clock cycle and throwing it off, but I just cant see how it could happen!



Code:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.Numeric_STD.all;


ENTITY	uC_Data_DeShifter IS
PORT(
	serial_data_clock	: 	IN STD_LOGIC;
	serial_data_in		:	IN STD_LOGIC;
	serial_clearToSend	:	OUT STD_LOGIC; 
	
	Word				:	OUT	STD_LOGIC_VECTOR(21 downto 0);
	WordReady			:	OUT STD_LOGIC;

	Clear				:	IN	STD_LOGIC;
	
	SyncSystemClock		: 	IN 	STD_LOGIC
	);
END uC_Data_DeShifter;

ARCHITECTURE main OF uC_Data_DeShifter IS

	shared variable	data_register : BIT_VECTOR(21 downto 0); 
	
	shared variable	word_counter : integer range 0 to 22 := 0;
	
	signal	propagate : std_logic := '0';

BEGIN 

	recv_data : PROCESS( serial_data_clock, Clear )
	BEGIN
	
		if Clear = '1' then
			
			word_counter := 0;
			serial_clearToSend <= '1';
			propagate <= '0';
			
		else
			if	serial_data_clock'event and serial_data_clock = '1' and propagate = '0' then
			
				serial_clearToSend	<= '0';		
				
				if 	word_counter < 21 then
					data_register(0) := to_bit(serial_data_in);
					data_register := data_register sll 1;
					
					word_counter := word_counter + 1;
					
				else
					data_register(0) := to_bit(serial_data_in);
					propagate <= '1';

				end if;
				
			end if;
		end if;
		
	END PROCESS;
	
	sync_proc : PROCESS( SyncSystemClock )
	BEGIN
		if SyncSystemClock'event and SyncSystemClock = '1' then
				
				if propagate = '1' then
					Word <= to_stdlogicvector(data_register);
					WordReady <= '1';
				else
					WordReady <= '0';
				end if;
		
		end if;
	END PROCESS;
		

END main;
 

Most likely, the problem can't be seen from your code, because the timing of external control signals is missing. But if clear is
released with a running serial clock, problems must be expected. It's also not guaranteed, that data_register is stable, when
it's latched in the second process. For a reliable syncronization, you have to synchronize propagate first.

In a full design, some kind of synchronized handshake between both clock domains will be necessary.
 

    sebmaster

    Points: 2
    Helpful Answer Positive Rating
Hi FvM,

Thanks for your reply.

The propagate signal and the second process were my attempt at trying to synchronize between the two clock domains. I am not quite sure what else I need to do to synchronize them, could you explain what is wrong with the method I have?

I did suspect a spurious signal on the serial clock but what Ive seen on my scope many of the times leads me to suspect otherwise, that is, the CTS is high until the first cycle of the 22 bit word. It then goes high for one cycle one bit before the end; if it was a spurious signal then CTS would be low before the start of the transmission.

As for the internal logic in the CPLD, the MAXII doesnt support signal tap so its difficult to judge. What I will do next though is place the SPI block along with some very simply dummy external logic to give it the expected commands and run it for as long as needed to be sure there is no error (once I've incorporated the proper syncing of course) (or discover that there is one).

I think it must be this, as the only other explanation is that word_counter is become corrupted somehow, and that can't happen in a logic circuit unless something is damaged surely?


(PS. Are you the same FvM who helped me with my jtag cable on the Altera forums?)
 

Presently, there's a (small) synchronization problem, due to the fact, that propagate may be slightly faster than data_register. Then you would latch incorrect data, if the clock edges coincide.

If the clocks are unrelated and have at least a small frequency difference, this would only happen occasionally. Unfortunately, this kind of errors is much more weird than permanent errors.

Regarding the main problem, I think the timing requirement for clear and serial_clock are obvious. If clear is released near to a clock rising edge ore asserted before cycle end, the design won't work reliably.

If this isn't the case, a ringing clock signal causing false clocking is a likely explanation. If serial_clock frequency is a quarter of your regular system clock or less, synchronous processing of the serial data would be a much better way and avoid synchronization issues. Otherwise a signal filtering must be considered.

Yes, it's me.
 

    sebmaster

    Points: 2
    Helpful Answer Positive Rating
Hi FvM,

In my tests I made sure I left enough time for the clear to be asserted and de-asserted before the next transmission. The point of the CTS line was so the uC would not start a transmission until Clear had been asserted, which is why I am having trouble synchronizing it.

I am modifying my code to output the contents of data_register before it asserts propagate in the main process to avoid the syncing problem you mentioned.

The serial clock is running at 330Khz while the system clock is running at 66Mhz, so this could be the problem with the ringing clock you mentioned.

This is just how I have it now for testing though, ideally I would bring it up to as close to the system clock as the micro-controller will allow.

The ringing clock does seem likely the waveform on the scope isn't exceptionally clean though I didn't think the overshoot seemed anywhere near large enough to be counted as a clock edge.
What do you think would be the best way to implement signal filtering? I heard that Altera doesn't support the AFTER keyword which is what I would have chosen.

One more thing, I am having trouble detecting my CPLD sometimes. I've just tried it with a known working PC and cable and I received a number of erroneous "unknown device" detections and integrity checking failures. There are usually about 50 of these before the device is successfully detected and can be programmed.

Do you think these problems could be related?
 

With 330kHZ, you should change your design to synchronous receiption.

Signal filtering for a clock input would involve an anlog circuit, it can't be achieved by the CPLD. But I think it's obsolete considering the low clock frequency.

The JTAG problems seem to indicate an unstable hardware, everything is possible in this case.
 

    sebmaster

    Points: 2
    Helpful Answer Positive Rating
Hi FvM, I was afraid of that - my board doesn't lend itself well to adding hardware filters at this stage.

I've added some pull up/down resistors to the JTAG points on the board and on the external inputs to the circuit, on the addition of the latter the JTAG seemed to stabalize much more. I am not sure if it was coincidence but I know the CPLD was picking up a considerable amount of noise as I could see it trying to process the SPI 'input'.

The JTAG isn't quite perfect at the moment I am still getting isolated "jtag chain uncertain" messages, and it could be a fluke at this point and fall apart again later but its gone from a 90% failure rate to a 99% success so i'm considering that good enough to turn my attention back to the design problem for now.

I'll post back when i'm more certain of its behaviour.

Thanks for your help.
 

TCK should have an 1k pull-down, otherwise it can easily catch interferences, the other JTAG lines are O.K.with 10k pull-up.
 

    sebmaster

    Points: 2
    Helpful Answer Positive Rating
Hi FvM,

Thanks.

The board is working much better now. I am not having any problems with the JTAG and the main problem with the design is more predictable now - i.e. its gotten considerably worse so at least now it looks like a VHDL error instead of hidden noise.

I've enclosed a shot of my scope during one write cycle. My uC has a max SPI word size of 11 bits so my program sends two which the CPLD is to treat as one.

The top trace is the SPI clock and the bottom is the CTS line.

The program running on the device is below.

With this program i've tried to make it behave as close as possible to my SPI design while removing the effects of external logic.
I also added a chip_enable line to try and elimate the affect of any spurious signals between transmissions, though there is nothing done to remove ringing if that is the problem yet.

Whats on the scope in the picture isn't always whats displayed; many times I wont see the CTS signal at all in the 22 clock cycles, sometimes its a very short pulse that could be mistaken for noise.

I chose the enclosed image because, looking at the code, if its synthesized correctly, shouldn't it be impossible to get that?

EDIT: Forgot to mention, I tried syncing everything to the main system clock within one process, and increasing the clock speed of the SPI to 66Mhz. Both times I got pretty much the same result as I am getting now.

EDIT: I just modified my uC code and cut the main system clock for the CPLD in half to ~35Mhz and it seems to be working. I can send the command that gives a visible result on the board continually and see it take affect in the main program, without the SPI slave 'losing its place'.

I am puzzled as to why this is, the timing analysis tool approved my design to run at 120Mhz, and the whole point was that the SPI functionality should be independant of this anyway.

Hopefully I can get it working at at least 50Mhz as this is the rate I would want ideally for my application, or, even better, figure out what the cause is :!:

Code:
Entity uC_Data_DeShifter IS
PORT(
	serial_data_clock	: 	IN STD_LOGIC;
	serial_data_in		:	IN STD_LOGIC;
	serial_clearToSend	:	OUT STD_LOGIC; 
	
	serial_chipenable	:	IN STD_LOGIC;	--active low
	
	Word				:	OUT	STD_LOGIC_VECTOR(21 downto 0);
	WordReady			:	OUT STD_LOGIC;

--	Clear				:	IN	STD_LOGIC;
	
	SyncSystemClock		: 	IN 	STD_LOGIC
	);
END uC_Data_DeShifter;

ARCHITECTURE main OF uC_Data_DeShifter IS

	shared variable	data_register : BIT_VECTOR(21 downto 0); 
	
	shared variable	word_counter : integer range 0 to 21 := 0;
	
	signal	propagate : std_logic := '0';
	
	signal	Clear : std_logic;

BEGIN 

	recv_data : PROCESS( serial_data_clock, Clear )
	BEGIN
	
		if Clear = '1' and propagate = '1' then
			
			serial_clearToSend <= '1';
			propagate <= '0';
			
		else
			if		serial_data_clock'event and serial_data_clock = '1' 
				and propagate = '0'
				and	serial_chipenable = '0' 
			then
			
				serial_clearToSend	<= '0';		
				
				if 	word_counter < 21 then
					data_register(0) := to_bit(serial_data_in);
					data_register := data_register sll 1;
					
					word_counter := word_counter + 1;
					
				else
					data_register(0) := to_bit(serial_data_in);
					Word <= to_stdlogicvector(data_register);
					
					propagate <= '1';
					word_counter := 0;

				end if;
				
			end if;
		end if;
		
	END PROCESS;
	
	sync_proc : PROCESS( SyncSystemClock )
	BEGIN
		if SyncSystemClock'event and SyncSystemClock = '1' then
				
				if propagate = '1' then
					Clear <= '1';
				else
					Clear <= '0';
				end if;
				
		end if;
	END PROCESS;
		

END main;
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top