Read incomming message in an Interrupt handler

Technical questions regarding the XTC tools and programming with XMOS.
neon
Junior Member
Posts: 7
Joined: Tue Nov 02, 2010 9:56 am

Read incomming message in an Interrupt handler

Post by neon »

Hello,

I try to establish a connection between two Task (running on seperate cores).

One task initalizes an Interrupt on the chan resource and the second sends a message.

My problem is now to read the message from the chanend in the Interrupt handler Function.
I didn´t know how to make the chan public in the Interrupt handler from whom I should read the incomming message.

Code: Select all

int main(void) {
	chan c1;
	par
	{
		on stdcore[0]: Core0(c1);
		on stdcore[1]: Core1(c1);
	}
  return 0;
}
void Core0(chanend chC0)
{

	printf("start transmission\n");
	chC0 <: 100;
	printf("end of transmission\n");

}
void Core1(chanend chC1)
{
	_v_InitInterrupt(chC1);
}
void ISR()
{
	unsigned int x;

	receive :> x; // here is the problem, i didn´t know how to make the chan public

	asm("kret");
}
The _v_InitInterrupt() function is an Assembler function

Code: Select all

	ldap	r11,		ISR		// get adr of interrupt handler
	setv	res[r0],	r11					// set the interrupt vector of the timer
      setc    res[r0],    XS1_SETC_IE_MODE_INTERRUPT		// CTRL_IE_MODE_INTERRUPT
	eeu 	res[r0]
	setsr   0x2		// enable interrupts	                                                               
Thanks in advance!

Bernhard


User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm

Post by Folknology »

Hi Bernhard

I am probably missing something subtle here in what your trying to achieve, but why are you using Interrupts instead of the standard event based channel coms?

regards
Al
neon
Junior Member
Posts: 7
Joined: Tue Nov 02, 2010 9:56 am

Post by neon »

Hi Al,

I use Interrupts because I need the option to interrupt a running task as part of a "Kernel Funcitonality"

regards
Bernhard
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm

Post by Folknology »

I don't think XC will let you do that. you will probably have to step down into C or ASM would be my guess.

regards
Al
neon
Junior Member
Posts: 7
Joined: Tue Nov 02, 2010 9:56 am

Post by neon »

Folknology wrote:I don't think XC will let you do that. you will probably have to step down into C or ASM would be my guess.
Al
I think the same way.

My first idea is to construct an ChanIdentifier by my self.

Composed of: NodeId | CoreId | Channelend | Value 2 . As described in the xsinst87.pdf (GETR)

But I´m not sure if this works correctly without an allocation of the resource

I will give this a try...tomorrow:)
User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

Can't you just use a global variable for it? In C you can, you could write your
interrupt routine in C if XC won't allow this. Or you can do some asm trickery
(to convert a chan id to an integer and back).
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm

Post by Folknology »

From the XC user manual - 3.3.1 Channel Disjointness Rules:
The rules for disjointness on a set of threads T0 . . . Ti and a set of channels C0 . . . Cj
are as follows:
• If threads Tx and Ty (where x = y) contain a use of channel Cy then none of
the other threads (Tt , t = x, y) are allowed use Cy .
• If thread Tx contains a use of channel end Cy then none of the other threads
(Tt , t = x) are allowed to use Cy .
In other words, each channel can be used in at most two threads. If a channel is
used in only one thread then attempting to input or output on the channel will block
forever.
The disjointness rules for variables and channels together guarantee that any two
threads can be run concurrently on any two processors, subject to a physical route
existing between the processors. As a general rule, threads that interact with one
another frequently should usually be located close together.
Not sure how that gets interpreted here, the interrupt isn't part of the par construct so isn't an XC thread in the normal sense. Also in XC a chan isn't the same as a chanend so how do you globalise that?

Thus I think it must require C or ASM

regards
Al
neon
Junior Member
Posts: 7
Joined: Tue Nov 02, 2010 9:56 am

Post by neon »

I just managed it.

As I wrote yesterday I tried to create an channel-end identifier manuell
From the xsinst87.pdf GETR instruction
If a channel end is allocated, a local channel end is returned. In order to connect
to a remote channel end, a program normally receives a channel-end over an
already connected channel, which is stored using SETD. To connect the first
remote channel, a channel-end identifier can be constructed (by concatenating
a node id, core id, channel-end and the value ’2’).
so my channel-end identifier is constructed as follow
InterruptChanend = 65794 = 0x10102
bit[0:7] resource type
bit[8:15] resource counter
bit[16:23] core ID
bit[24:31] node ID

Don´t know if this is the best solution...nevertheless here is the code :)

Code: Select all

int GlobalTemp;
unsigned int InterruptChanend = 65794;
int main(void) {
	chan c1;
	par
	{
		on stdcore[0]: Core0(c1);
		on stdcore[1]: Core1(c1);
	}
  return 0;
}
void Core0(chanend chC0)
{
	int counter = 3;
	printf("start transmission\n");
		chC0 <: counter;
	printf("end of transmission\n");
}
void Core1(chanend chC1)
{
	_v_InitInterrupt(chC1);

	while(1)
	{
		printf("core1: %i\n", GlobalTemp);
	}
}
Assembler Funktion _v_InitInterrupt()

Code: Select all

	ldap	r11,		Interrupthandler	// get adr of interrupt handler
	setv	res[r0],	r11					// set the interrupt vector of the timer
    setc    res[r0],    XS1_SETC_IE_MODE_INTERRUPT		// CTRL_IE_MODE_INTERRUPT
	eeu 	res[r0]
	setsr   0x2		// enable interrupts
Interrupt hanlder in Assembler

Code: Select all

clrsr 0x2

ldw   r0, dp[InterruptChanend]
chkct res[r0], 0x1
ldw   r0, dp[InterruptChanend]
outct res[r0], 0x1
ldw   r0, dp[InterruptChanend]
in    r0, res[r0]
stw   r0, dp[GlobalTemp] // save Message in global Variable
ldw   r0, dp[InterruptChanend]
chkct res[r0], 0x1
ldw   r0, dp[InterruptChanend]
outct res[r0], 0x1

setsr 0x2
kret
richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

The channel end is passed as an argument to _v_InitInterrupt(). Why not just store the resource ID to the global at this point with

Code: Select all

stw r0, dp[InterruptChanend]
This way the code won't break horribly in future if something changes to cause a different channel end to be allocated.

The clrsr 0x2 and setsr 0x2 instructions in interrupt handler are unnecessary and should be removed - The processor will disable events and interrupts on the thread whenever an interrupt is taken and restore the previous state of these sr bits on returning with kret.

Finally your interrupt handler clobbers r0. This is fine if the code you interrupt never uses r0 but since you are interrupting compiled code you can't make this assumption. You could deal with this by saving r0 off to a global on entry to the interrupt handler and restoring it before returning. Apart from these things the code looks good.
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm

Post by Folknology »

I would also assume like yourself that the XC compiler isn't bothered that GlobalTemp isn't constant or initialised/written too as long as the threads only ever read from it. I'm guessing the compiler only ever looks at global variable writes to detect disjointedness. You might want to add some thread reads just in case to confim that!

regards
Al