Are shared output ports possible?

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
landon
Experienced Member
Posts: 71
Joined: Mon Sep 06, 2010 4:05 pm

Are shared output ports possible?

Post by landon »

I have what seems like a simple need and that is for one thread to turn an LED on and another thread to turn it off. The output port is a variable and variables can't be read/write shared across threads which makes it impossible, I think, for two threads to use the same port in this way. The compiler errors out with "...violates parallel usage rules."

What is the typical approach used to deal with shared ports? Channels have two ends (at least in XC I can't have a multi-end-to-one-end channel, correct?), so I couldn't create another thread with a channel that could service two other threads.

How would you ever share a resource like a port between threads? Is it possible to do in XC without creating a new channel for each thread to talk to a single thread which has write access to the port?

Still cutting my teethe on XMOS, understand XMOS XC conventions for getting basic things done (and probably will be for months - TIA for your help),

Landon


User avatar
rp181
Respected Member
Posts: 395
Joined: Tue May 18, 2010 12:25 am

Post by rp181 »

I think you do have to have multiple threads, a owner thread, and n amount of threads that need to control it. The owner would just have a channel to each, and listen on all of them.
User avatar
landon
Experienced Member
Posts: 71
Joined: Mon Sep 06, 2010 4:05 pm

Post by landon »

Ok, just to put a cap on this, I wrote this example which shows two threads sharing an LED port via a 3rd thread which is communicating with the first two threads via separate channels. thing1() is turning on the LED and thing2() is turning it off. led_manager() starts thing1 and thing2 with two different channels and then listens to both waiting for the first input of either, sets the input to 'led' and led is used to set the LED ports state.

Seems like there should be an easier way to do this simple thing, but maybe not. If so, feel free to suggest it - I would like to learn.

Code: Select all

#include <xs1.h>
#include <platform.h>

// LEDs
#define IO_CORE 0
on stdcore[IO_CORE] : out port p_leds_3_0 = XS1_PORT_4F;

#define LED_DELAY   1000000

void thing1(chanend channel1)
{
	timer t;
	unsigned time;

	while( 1 )
	{
		t :> time;
		time += LED_DELAY;
		t when timerafter(time) :> void;

		channel1 <: 1;  // on
	}

}

void thing2(chanend channel2)
{
	timer t;
	unsigned time;

	while( 1 )
	{
		t :> time;
		time += LED_DELAY + 25000;
		t when timerafter(time) :> void;

		channel2 <: 0; // off
	}
}


void led_manager()
{
	int led;
	chan chan1, chan2;

	par {
		thing1( chan1 );
		thing2( chan2 );
		while( 1 )
		{
			// listen to channel 1 and 2, modify LED
			select {
			case chan1 :> led :
				break;
			case chan2 :> led :
				break;
			}

			p_leds_3_0 <: led; // gonna be a 0 or 1 - single LED
		}
	}
}


int main()
{
  par
  {
      on stdcore[IO_CORE] : led_manager();
  }
  return 0;
}
ale500
Respected Member
Posts: 259
Joined: Thu Sep 16, 2010 9:15 am

Post by ale500 »

There is a way. You just do a simple assembler routine that outputs the value you want to the port. remember it is the compiler the one that complains :). But be aware of some nasty bugs you may introduce by using this technique a bit too liberally :)
User avatar
Bianco
XCore Expert
Posts: 754
Joined: Thu Dec 10, 2009 6:56 pm

Post by Bianco »

ale500 wrote:There is a way. You just do a simple assembler routine that outputs the value you want to the port. remember it is the compiler the one that complains :). But be aware of some nasty bugs you may introduce by using this technique a bit too liberally :)
I think it will be fine if you use a lock around the code that deals with the port.

Possible issues are that two instructions accessing the same port from different threads are in the pipeline, a lock will prevent that. Second if you use events on the port and a different thread accesses the port, the event will be fired to the last thread that has accessed the port, so don't use events.