How to sync output to ports on tile0 and tile1

If you have a simple question and just want an answer.
martinh
Member++
Posts: 19
Joined: Thu Oct 01, 2015 10:55 am

How to sync output to ports on tile0 and tile1

Post by martinh »

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.
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am

Post by mon2 »

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

martinh
Member++
Posts: 19
Joined: Thu Oct 01, 2015 10:55 am

Post by martinh »

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.
 
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am

Post by mon2 »

#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.

 

martinh
Member++
Posts: 19
Joined: Thu Oct 01, 2015 10:55 am

Post by martinh »

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?
martinh
Member++
Posts: 19
Joined: Thu Oct 01, 2015 10:55 am

Post by martinh »

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
 

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.