Hello,
I am evaluating the x-CORE-200 eExplorer board.
The aim is to output data to one port on tile1 and one port on tile0 every 40ns absolutely synchronously.
So a clock clk=25MHz was created on tile1 and after some optimization to the output routine everyting works fine.
To get 2 synchronous clocks on both tiles I output clk to P1B on tile1 and input that signal on P10 of tile0 and tile1. The clocks
now are synchonous on both tiles. (That is what can be seen on the scope when both clocks are output to a separate port.)
The problem comes up when an external enable signal shall start a routine on tile0 and tile1 absolutely synchronously.
For tile1:
select {
case pStartPinging when pinsneq(x1) :> void:
pOut1 <: 1; // a buffered port on tile1
// to trigger an oscilloscope
....
For tile0
select {
case pStartPinging0 when pinsneq(x0) :> void:
pOut1_T0 <: 1; // a buffered port on tile0
...
The clock for each out-port is the clock taken from the in-ports on each tile, i.e. synchronous clocks.
The issue is that the signal at pOut1_T0 jitters by 40ns compared to pOut1.
The rise time of the external enable signal is about 7ns and the positive going edge shows some ringing. Could that cause the jitter?
It looks like the case statements detect the HIGH state at different levels while the positive edge is rising. That sounds odd, I know.
Increasing the output periode from 40ns to 80ns or adding something like
pOut1 <: 0;
sync(pOut1);
after each case statement did not help.
Does anybody know how to get rid of the problem or has a suggestion?
Thank you.
Regards,
Martin H.
How to sync output to ports on tile0 and tile1
-
- Member++
- Posts: 19
- Joined: Thu Oct 01, 2015 10:55 am
-
- XCore Legend
- Posts: 1913
- Joined: Thu Jun 10, 2010 11:43 am
Try a different approach than the select method to sample your multiple ports.
See section 6.10 inside this document for an example:
https://www.xmos.com/zh/node/17653?page=26
See section 6.10 inside this document for an example:
https://www.xmos.com/zh/node/17653?page=26
-
- Member++
- Posts: 19
- Joined: Thu Oct 01, 2015 10:55 am
Thanks for replying.
I need to output shorts simultaneously from 2 arrays located on two different tiles. The arrays are located in RAM memory of each tile.
AFAIK a task can only access resources on the actual tile. Sending data from one task to another requires to much time as each short must be grabbed and output within 40ns.
It is the lack of time why the recommended procedure cannot be used.
Any other ideas?
Regards,
Martin H.
I need to output shorts simultaneously from 2 arrays located on two different tiles. The arrays are located in RAM memory of each tile.
AFAIK a task can only access resources on the actual tile. Sending data from one task to another requires to much time as each short must be grabbed and output within 40ns.
It is the lack of time why the recommended procedure cannot be used.
Any other ideas?
Regards,
Martin H.
-
- XCore Legend
- Posts: 1913
- Joined: Thu Jun 10, 2010 11:43 am
#include <xs1.h>
#include <platform.h>
#include <timer.h>
// change the definitions & labels to suit
on tile[0] : out buffered port :8 pOut1_T0 = XS1_PORT_8B; // buffered output port on Tile[0]
on tile[1] : out buffered port :8 pOut1_T1 = XS1_PORT_8B; // buffered output port on Tile[1]
// to automate the output of 32 bits on 8 bit port
//on tile[0] : out buffered port :32 pOut1_T0 = XS1_PORT_8B; // buffered output port on Tile[0]
//on tile[1] : out buffered port :32 pOut1_T1 = XS1_PORT_8B; // buffered output port on Tile[1]
// feed the external clock here (change to any free SINGLE bit port to suit)
on tile[0] : in port clk_T0 = XS1_PORT_1A; // input port for external CLK on Tile[0] (must be single bit port for CLK)
on tile[1] : in port clk_T1 = XS1_PORT_1A; // input port for external CLK on Tile[1] (must be single bit port for CLK)
// code to run on Tile[0]
void output_tile0()
{
char x;
int send0 [10] = {0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa};
configure_clock_src (clk , clk_T0 );
configure_out_port pOut1_T0 , clk , 0);
start_clock (clk);
x=0;
pOut1_T0 <: 0; // start an output
sync( pOut1_T0 ); // synchronize to falling edge
while (1) {
pOut1_T0 <: send0[x++]; // data to output
if (x>=10) x=0;
}
}
// code to run on Tile[1]
void output_tile1()
{
char x;
int send1 [10] = {0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a};
configure_clock_src (clk , clk_T1 );
configure_out_port pOut1_T1 , clk , 0);
start_clock (clk);
x=0;
pOut1_T1 <: 0; // start an output
sync( pOut1_T1 ); // synchronize to falling edge
while (1) {
pOut1_T1 <: send1[x++]; // data to output
if (x>=10) x=0;
}
}
int main() {
par{
on tile[0]: output_tile0();
on tile[1]: output_tile1();
}
return 0;
}
Disclaimer: Code has not been compiled nor tested but should compile ok. Post back your results. Believe that the above idea should meet your requirements.
#include <platform.h>
#include <timer.h>
// change the definitions & labels to suit
on tile[0] : out buffered port :8 pOut1_T0 = XS1_PORT_8B; // buffered output port on Tile[0]
on tile[1] : out buffered port :8 pOut1_T1 = XS1_PORT_8B; // buffered output port on Tile[1]
// to automate the output of 32 bits on 8 bit port
//on tile[0] : out buffered port :32 pOut1_T0 = XS1_PORT_8B; // buffered output port on Tile[0]
//on tile[1] : out buffered port :32 pOut1_T1 = XS1_PORT_8B; // buffered output port on Tile[1]
// feed the external clock here (change to any free SINGLE bit port to suit)
on tile[0] : in port clk_T0 = XS1_PORT_1A; // input port for external CLK on Tile[0] (must be single bit port for CLK)
on tile[1] : in port clk_T1 = XS1_PORT_1A; // input port for external CLK on Tile[1] (must be single bit port for CLK)
// code to run on Tile[0]
void output_tile0()
{
char x;
int send0 [10] = {0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa};
configure_clock_src (clk , clk_T0 );
configure_out_port pOut1_T0 , clk , 0);
start_clock (clk);
x=0;
pOut1_T0 <: 0; // start an output
sync( pOut1_T0 ); // synchronize to falling edge
while (1) {
pOut1_T0 <: send0[x++]; // data to output
if (x>=10) x=0;
}
}
// code to run on Tile[1]
void output_tile1()
{
char x;
int send1 [10] = {0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a};
configure_clock_src (clk , clk_T1 );
configure_out_port pOut1_T1 , clk , 0);
start_clock (clk);
x=0;
pOut1_T1 <: 0; // start an output
sync( pOut1_T1 ); // synchronize to falling edge
while (1) {
pOut1_T1 <: send1[x++]; // data to output
if (x>=10) x=0;
}
}
int main() {
par{
on tile[0]: output_tile0();
on tile[1]: output_tile1();
}
return 0;
}
Disclaimer: Code has not been compiled nor tested but should compile ok. Post back your results. Believe that the above idea should meet your requirements.
-
- Member++
- Posts: 19
- Joined: Thu Oct 01, 2015 10:55 am
Sorry for the late reply.
With
on tile[0] : clock clk = XS1_CLKBLK_1;
the compiler still complains saying
error: use of `clk' violates parallel usage rules
I have corrected that by using a different clock name on each tile.
But how would one make sure that outputs are exactly synchronous?
I could try running start_clock(..) for the external clock as soon as the Start signal has been detected and stop_clock(...) when output is finished.
Would that be the recommended procedure?
With
on tile[0] : clock clk = XS1_CLKBLK_1;
the compiler still complains saying
error: use of `clk' violates parallel usage rules
I have corrected that by using a different clock name on each tile.
But how would one make sure that outputs are exactly synchronous?
I could try running start_clock(..) for the external clock as soon as the Start signal has been detected and stop_clock(...) when output is finished.
Would that be the recommended procedure?
-
- Member++
- Posts: 19
- Joined: Thu Oct 01, 2015 10:55 am
It does not work, but I found a (not satisfying) workaround.
It seems that the problem comes up when 2 ports on different tiles monitor the same external event. Most likely he negative
clocking edge must not coincide with the rising edge of the monitored signal to guarantee absolutely simultaneous reactions on both tiles (select statement). With a clock of 25MHz and an output each 40ns this can happen very often.
The idea was to detect the external event using one port on tile0 while the clock of the outports has not yet been started, then adding a delay of one clock to leave the rising edge of the event signal and then starting the clock named clk. clk is input to each tile to produce synchronous clocks for data output. With that I expected synchronous out signals on each tile.
1. What NOT WORKS
On tile0:
while(1) {
select {
case pInStart0 when pinsneq(y0) :> y0: // wait for external event
pOutStart0 <: 1; // just to trigger the scope
sync(pOutStart0); // and delay to get out of the rising edge
start_clock(clk); // clock that is fed to both
//tiles for clocking the out-ports
break;
// this should only run when the clock has been started:
case pStartPinging0 when pinsneq(x0) :> x0:
DoPing0(iLen); // same as DoPing() above but usese port XS1_PORT_4D,
// (shall be changed to a 16 bit port later)
pOutStart0 <: 0; // just for triggering the scope
y0 = 0;
x0 = 0;
stop_clock(clk);
break;
}
}
And this is what can be seen on the scope:
Sorry,this is where the image should be. But for some reason I could not insert it.
Please see attachment!
Fig.: Delayed data output
yellow: clocks the port to output data with DoPing0() and DoPing()
Additionally these clocks have been output via a separate port on
each tile to check that they are synchronous.
green: the external event
cyan: data output on tile1
magenta: data output on tile0
It can be seen that there is a delay of 240ns even though both tiles get their output clock at the same time.
Also it seems that there are more clock cycles than expected before data is output.
Useless for me.
2. The workaround
Data output becomes synchronous if the output data on tile1 is delayed
Adding
pPing <: 0;
pPing <: 0;
sync(pPing);
pPing <: 0;
sync(pPing);
before DoPing(iLen) is called provides synchronisation.
The drawback is that each time clk (the clock that is started and stopped) is changed to a different frequency, data output is out of sync.
So it is not a really good workaround.
My questions to the experts would be what went wrong?
Does anybody know or can give me a hint?
That would help a lot.
Thank you.
Regards,
Martin H.
It seems that the problem comes up when 2 ports on different tiles monitor the same external event. Most likely he negative
clocking edge must not coincide with the rising edge of the monitored signal to guarantee absolutely simultaneous reactions on both tiles (select statement). With a clock of 25MHz and an output each 40ns this can happen very often.
The idea was to detect the external event using one port on tile0 while the clock of the outports has not yet been started, then adding a delay of one clock to leave the rising edge of the event signal and then starting the clock named clk. clk is input to each tile to produce synchronous clocks for data output. With that I expected synchronous out signals on each tile.
1. What NOT WORKS
Code: Select all
On tile1 while(1) { select { case pInStart0 when pinsneq(y0) :> y0: // wait for external event pOutStart0 <: 1; // just to trigger the scope sync(pOutStart0); // and delay to get out of the rising edge start_clock(clk); // clock that is fed to both tiles for clocking the outports break; // this should only run when the clock has been started case pStartPinging0 when pinsneq(x0) :> x0: DoPing0(iLen); // same as DoPing() above but usese port XS1_PORT_4D, // (shall be changed to a 16 bit port later) pOutStart0 <: 0; // just for triggering the scope y0 = 0; x0 = 0; stop_clock(clk); break; } }
On tile0:
while(1) {
select {
case pInStart0 when pinsneq(y0) :> y0: // wait for external event
pOutStart0 <: 1; // just to trigger the scope
sync(pOutStart0); // and delay to get out of the rising edge
start_clock(clk); // clock that is fed to both
//tiles for clocking the out-ports
break;
// this should only run when the clock has been started:
case pStartPinging0 when pinsneq(x0) :> x0:
DoPing0(iLen); // same as DoPing() above but usese port XS1_PORT_4D,
// (shall be changed to a 16 bit port later)
pOutStart0 <: 0; // just for triggering the scope
y0 = 0;
x0 = 0;
stop_clock(clk);
break;
}
}
And this is what can be seen on the scope:
Sorry,this is where the image should be. But for some reason I could not insert it.
Please see attachment!
Fig.: Delayed data output
yellow: clocks the port to output data with DoPing0() and DoPing()
Additionally these clocks have been output via a separate port on
each tile to check that they are synchronous.
green: the external event
cyan: data output on tile1
magenta: data output on tile0
It can be seen that there is a delay of 240ns even though both tiles get their output clock at the same time.
Also it seems that there are more clock cycles than expected before data is output.
Useless for me.
2. The workaround
Data output becomes synchronous if the output data on tile1 is delayed
Adding
pPing <: 0;
pPing <: 0;
sync(pPing);
pPing <: 0;
sync(pPing);
before DoPing(iLen) is called provides synchronisation.
The drawback is that each time clk (the clock that is started and stopped) is changed to a different frequency, data output is out of sync.
So it is not a really good workaround.
My questions to the experts would be what went wrong?
Does anybody know or can give me a hint?
That would help a lot.
Thank you.
Regards,
Martin H.
You do not have the required permissions to view the files attached to this post.