Edge triggering?

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
Woody
XCore Addict
Posts: 165
Joined: Wed Feb 10, 2010 2:32 pm

Post by Woody »

Glad to hear it works. It's quite a nice solution I think.

Interrupts have been included in the XCore to allow us to support the migration of legacy code. XC uses events (rather than interrupts) exclusively and you will nearly always find that it is quicker to write an app written in XC. It will also be easier to support than the assembler you'll need to write to implement and integrate an interrupt.

Anyway, you get the message that if you're writing code with interrupts in assembler, you'll meet the same problems writing the code that you'd have on other processors (the problems Xmos avoids by using event driven, XC coding etc.). To answer your question directly now, the interrupts are described in the XS1 architecture manual (http://www.xmos.com/system/files/xs1_en.pdf) in the 'Events, Interrupts and Exceptions' chapter.


User avatar
TonyD
XCore Addict
Posts: 234
Joined: Thu Dec 10, 2009 11:11 pm
Location: Newcastle, UK

Post by TonyD »

JohnR wrote:...
I still need clean up the code - I need to handle the case when there is no second pulse - as well as to tidy up the LCD display code. Then maybe I will post it in the projects section.
John, please post it. I'm sure there will be many others interested in seeing it.
JohnR
Experienced Member
Posts: 93
Joined: Fri Dec 11, 2009 1:39 pm

Post by JohnR »

Woody,

Thanks for your last message re using interrupts. I had thought that the latency responding to an input pulse might have been less with interrupts as compared to events. In any case, now I have two parallel threads for start and stop both with the same latency, this really does not matter any more.

I added another thread to handle the display code thus

Code: Select all

par {
		start_channel(start, c_start);
		stop_channel(c_stop, stop);
		process(c_start, c_stop, c_data, test);
		display(c_data);
	}
Re usage of assembly - I have been coding in XC to start with and then looking at the generated assembler output. I have found that the assembler (even in 03 ?) mode seems to favour using a minimal number of registers that sometines require a lot of reloading from memory, fixed by adding some more registers at the start of the function. In some other cases the assembler seems not to look ahead, as in this code fragment,

Code: Select all

..L10:
          mkmsk     r2, 0x1
          ldw       r1, dp[start] 
          setd      res[r1], r2
          ldw       r1, dp[start] 
          setc      res[r1], 0x11
          ldw       r1, dp[start] 
.L13:
          in        r1, res[r1] 
          ldw       r1, dp[start] 
          getts     r3, res[r1] 
.L13:
 


As far as I can see the second and third ldw's are unnecessary?

TonyD,

Thanks for your encouragement. I still have to get the case of no stop pulse working.

Right now I am using the code below but it still needs debugging.

Code: Select all

				case stop when pinseq(1) :> void @ tStop:
					c_stop <: tStop;
				break;
				case t when timerafter(time) :> void :
					c_stop <: time;
				break;
			}
			t :> time;
			time += 5000;
As soon as it is all working, I will post the code trivial though it is.

John
JohnR
Experienced Member
Posts: 93
Joined: Fri Dec 11, 2009 1:39 pm

Post by JohnR »

Hi Woody,

Maybe you could help me again with a question on timed input ports. I have now implemented my delay measurement system using two threads to respond to the start and stop pulses.

Code: Select all

void start_channel(in port  start, streaming chanend c_start)
{
	int tStart;

	while (1) {
		if(peek(start)==0 ){
			start when pinseq(1) :> void @ tStart;
			c_start <: tStart;
		}
	}
}

void stop_channel(in port  stop, streaming chanend c_stop)
{
	int tStop;

	while (1) {
		if(peek(stop)==0) {
			stop when pinseq(1) :> void @ tStop;
			c_stop <: tStop;
		}
	}
}


I accumulate the delay value (c_stop - c_start) over a million pulses. If I plot the response for pulse delays between from about 15nsecs (the minimum delay I can generate) to about 140 nsecs, the delay value is given by

value = 200000 * delay + 24800000 where delay is in nsecs.

I am totally puzzled by the big offset value. I had expected that with the two inputs now on separate threads with identical code that there would be no offset as the time stamps would be, I thought, synchronous being generated from the same clock source. The reference frequency, as set up in the xml file, is 200Mhz. The input data rate is 1Mhz.

The offset really is no problem as I can simply subtract it in subsequent data processing but I am curious as to why it is occurring. Any help would again be appreciated.


John
JohnR
Experienced Member
Posts: 93
Joined: Fri Dec 11, 2009 1:39 pm

Post by JohnR »

Hi,

I have added my current version of the timer code, warts and all, to the XCore project section.

Woody wrote earlier
Hi,

Quote:
The timestamping is performed by the hardware associated with the port circuitry. You need to have two threads to make sure that both ports are setup to look for the condition and store the timestamp. When the threads are setup like this the time it takes to read the timestamps is irrelevant.
I think this is strictly true only when two separate cores are used. In the case of two threads on a single core, the input processing seems first to handle the start pulse, then process the second pulse. This minimum "processing" time seems to be of the order of 100 nsecs. It is really not a problem in practice since this time is constant and can be subtracted from the measured delays.

I naiively thought originally that the timestamp associated with the 'in' instruction was somehow generated within the instruction itself, in fact the assembler code shows it as a separate and subsequent instruction.

John.
JohnR
Experienced Member
Posts: 93
Joined: Fri Dec 11, 2009 1:39 pm

Post by JohnR »

Hi,

The table below shows the data from a set of delay measurements. The data in the output column is divided by a factor of 1000 from raw data accumulated over 1 sec measurement intervals at a 1 Mhz sampling rate.

Delay(ns) Output
16 15551
28 17557
32 18557
40 20054
50 22557
64 25060
78 27560
92 30070
104 32558
112 35052
128 37560
142 40043


John
User avatar
Woody
XCore Addict
Posts: 165
Joined: Wed Feb 10, 2010 2:32 pm

Post by Woody »

JohnR wrote:I accumulate the delay value (c_stop - c_start) over a million pulses. If I plot the response for pulse delays between from about 15nsecs (the minimum delay I can generate) to about 140 nsecs, the delay value is given by

value = 200000 * delay + 24800000 where delay is in nsecs.

I am totally puzzled by the big offset value. I had expected that with the two inputs now on separate threads with identical code that there would be no offset as the time stamps would be, I thought, synchronous being generated from the same clock source. The reference frequency, as set up in the xml file, is 200Mhz. The input data rate is 1Mhz.
I can't work out what is represented by the equation. What do you mean by 'value' and what do you mean by 'delay'? Hopefully we'll be able to get to the bottom of this.
JohnR
Experienced Member
Posts: 93
Joined: Fri Dec 11, 2009 1:39 pm

Post by JohnR »

Hi,
I can't work out what is represented by the equation. What do you mean by 'value' and what do you mean by 'delay'? Hopefully we'll be able to get to the bottom of this.
I apologise for not being clearer. The 'delay' is the value of the delay between the start and stop pulses as measured by my logic analyser, with a resolution, I believe, of 2 nsecs or so.

The 'value' is the output of the measurement system as shown on the HD44780 display. This is the accumulation of the differences in timestamps for 1 million start/stop pairs.

Hope this helps,

John.
User avatar
Woody
XCore Addict
Posts: 165
Joined: Wed Feb 10, 2010 2:32 pm

Post by Woody »

JohnR wrote:
Woody wrote:The timestamping is performed by the hardware associated with the port circuitry. You need to have two threads to make sure that both ports are setup to look for the condition and store the timestamp. When the threads are setup like this the time it takes to read the timestamps is irrelevant.
I think this is strictly true only when two separate cores are used. In the case of two threads on a single core, the input processing seems first to handle the start pulse, then process the second pulse. This minimum "processing" time seems to be of the order of 100 nsecs. It is really not a problem in practice since this time is constant and can be subtracted from the measured delays.

I naiively thought originally that the timestamp associated with the 'in' instruction was somehow generated within the instruction itself, in fact the assembler code shows it as a separate and subsequent instruction.

John.
Hi John,
I must correct the statement I made above. This is a full description of the timestamping operation:

a) If an event is used to perform a timestamped input, then the time is stored and can be read at any time
b) If a timestamped input is performed without creating an event, then the time is not stored. Instead, the port time will be read soon after the input completes. Usually this port time will be the same as if the port time has been stored. However, when a high speed port clock is used (200MHz in your case), this may result in the time being read not corresponding to the time the condition occurred.

So to make sure you get the correct timestamp, you need to force an event to be taken. To force an event to be created for timestamped inputs replace your timestamped input that looks like this:

Code: Select all

// Timestamped input without event
start when pinseq(1) :> void @ tStart;
with this

Code: Select all

// Timestamped input with event
select {
  start when pinseq(1) :> void @ tStart:
    break;
}
Sorry for the confusion on this. Can you implement the change and then see if you still get the same problem.
JohnR
Experienced Member
Posts: 93
Joined: Fri Dec 11, 2009 1:39 pm

Post by JohnR »

Hi Woody,

The results are almost exactly the same with the same data offset

The logic analyser port, test0 , connected as shown below in the 'process' function shows a delay of 120 ns when the input delay is around 20 ns

Code: Select all

void process(streaming chanend c_start, streaming chanend c_stop, streaming chanend c_data)
{
.....................
	while(1){
		select
		{
			case c_start :> start:
				test0 <: 1;
				temp = 0;
			    break;			
			case c_stop :> stop:
				test0 <: 0;
				temp = stop - start;
			    break;			
			default:
				break;
		}
/
[img]C:\XMos\pulser1.bmp
[/img]
It still seems to me that the single processor is reading time data in some sequential fashion rather than a hardware-generated time value?
John.