Hello,
it seems there is just no any mechanism raising an event for output ports... (please xmos team confirm or not).
Then I propose a way to mitigate this, by controlling variation of the "ts" (timestamp) register attached to the ports.
The ts register is set to the value of the port counter each time there is a transfer between the serdes (serialization) register and the transfer register (also called fifo).
in the following code example, the port pp is declared buffered 32 and is by default clocked by CLKBLK_REF so 100mhz.
this requires 32 cpu clock to shift out all the serialization register.
Code: Select all
#define gettime(_x) asm volatile("gettime %0":"=r"(_x))
#define getts(_x,_p) asm volatile("getts %0, res[%1]":"=r"(_x):"r"(_p));
buffered out port:32 pp = { your_1bit_port };
void mytask(){
unsigned ts0, ts1, t0, t1;
pp <: 0; // fill serdes register and start outputing 32 bits one by one (non blocking)
getts(ts0,pp); // get the latest value ot timestamp counter
gettime(t0); // capture cpu time
pp <: 0; // fill transfer register (fifo), non blocking for first time
pp <: 0; //wait for filling transfer register as fifo is now full
pp <: 0; //same
//sync(pp); //wait total end of serialization
gettime(t1); // capture cpu time
delay_ticks(100); //to ensure that serialization is completely finished
getts(ts1,pp);
printf("time= %d, ts1-ts0= %d, n= %d, \n",t1-t0-1, ts1-ts0,n);
}
running this program will print:
time= 64, ts1-ts0= 96, n= 0
the 2 first port-outputs (pp <: 0) are non blocking. but the 2 others will be waiting for the readiness of the transfer-register, so 32 cpu cycle each.
Therefor the cpu time taken by these 4 port-outputs will be "time= 64" only.
then we have a delay_ticks(100) before reading the ts value and we get "ts1-ts0= 96", because the transfer register has been transferred into the serdes register only 3 times, not four. whatever you wait , it will never show 128 but stays at 96.
removing the // before the sync(pp) change the game and will print:
time= 128, ts1-ts0= 96, n= 0
we can see that sync(pp) is waiting the serialization to be completely finished, including the latest value held in the transfer register.
so we get "time= 128" cpu cycles which perfectly correspond to the 4 x 32 bits serialization.
Still the timestamp register doesn't change and is stuck with "ts1-ts0= 96"
So, it is possible to use the cpu time between 2 port-outputs access by checking the variation of the timestamp register, as per the example below:
Code: Select all
void mytask(){
unsigned ts0, ts1, ts2, t0, t1, n= 0;
pp <: 0; // fill serdes register and start outputting 32 bits one by one
getts(ts0,pp); // provide the last and unknown value ot timestamp counter
gettime(t0); // timestamp starting point
pp <: 0; // fill transfer register (fifo), non blocking for first time
do { n++; getts(ts1,pp); } while (ts0 == ts1); //this will wait a transfer between fifo and serdes register
pp <: 0; //fill fifo which is now empty (non blocking)
do { n++; getts(ts2,pp); } while (ts2 == ts1); //wait next transfer
pp <: 0; //fill buffer which is now empty (non blocking)
do { n++; getts(ts1,pp); } while (ts2 == ts1); //wait next transfer
//sync(pp); //wait total end of serialization
gettime(t1); // timestamp end of code
printf("time= %d, ts1-ts0= %d, n= %d\n",t1-t0-1, ts1-ts0,n);
}
running this program will print:
time= 100, ts1-ts0= 96, n= 24
so we were able to compute "n=24" using cpu time available between each port access.
time = 100 instead of time = 96 is just because the last do/while loop brings 4 extra instructions to execute its last cycle (a while/do) might be better here).
we also see that "ts1-ts0= 96" prooves that we have used all the possibilities given by this solution.
remark, it is not possible to detect any changes after the very first port-output as there is no fifo-serdes transfer, but a direct access to the serdes register.
after a very first port-output, it seems that the fifo mechanism with transfer and timestamp capture always works , even if the fifo becomes empty at some point in time.
this is demonstrated with the code example:
Code: Select all
void mytask(){
unsigned ts0, ts1, ts2;
pp <: 0; // fill serdes register and start outputting 32 bits one by one
getts(ts0,pp); // get the last value ot timestamp
delay_ticks(100); //creates a fifo empty situation as this is longer than serialization time
getts(ts1,pp); // get the last value of timestamp (unchanged here)
pp <: 0; // fill the empty fifo which seems to trigger an immediate transfer to serdes
getts(ts2,pp); // get timestamp
printf("1st ts = %d\n",ts1-ts0);
printf("2nd ts = %d\n",ts2-ts1);
}
which is printing:
1st ts = 0
2nd ts = 103
hope this helps someone !
remark2: as an example with this solution, it would be possible to modernize the xua_audio.xc of the usb software audio application by using a while(1) select with cases for managing client-server xc interface with decouple task, and the default statement could update lrclk and the adc/dac registers once the ts variation shows that the fifo is empty ready to accept a new sample...