Read 8 buffered ports at the same time

If you have a simple question and just want an answer.
zhy44th
Member
Posts: 11
Joined: Mon Dec 18, 2017 9:58 am

Read 8 buffered ports at the same time

Post by zhy44th »

I am going to use XL216 series chip to do the work of AD acquisition, AD model is AD7768, the AD data clock frequency is 8M, (125ns); 32 data patterns, I sample while DRDY signal is high, adopt 1 port 32 bit to buffer AD data. Taken every 32 clocks.
Since the DRDY signal time is only about 40 ns, and the sampling statement executes about 10 ns per step, the data in the following several channels is misaligned. I would like to know if eight channels can be sampled at the same time.

Code: Select all

//port config:
           on tile[0] : clock clk = XS1_CLKBLK_1;
           on tile[0] : in port p_clk_in = XS1_PORT_1I;//using  external AD CLK
           on tile[0] : in port p_rd = XS1_PORT_1J;// DATA READY SIGNAL
           on tile[0] : in buffered port:32 chan_1 = XS1_PORT_1L;//DATA CHANNEL
           on tile[0] : in buffered port:32 chan_2 = XS1_PORT_1K;
           on tile[0] : in buffered port:32 chan_3 = XS1_PORT_1M;
           on tile[0] : in buffered port:32 chan_4 = XS1_PORT_1N;
           on tile[0] : in buffered port:32 chan_5 = XS1_PORT_1O;

...
          //wait for data ready signal which last about 40ns. it's not enough.

            select
            {
                case p_rd  when  pinsneq(0):> cmd:
                //delay_ticks(1);
                chan_1:> valdata1[k];
                clearbuf(chan_1);
                chan_2:> valdata2[k];
                clearbuf(chan_2);
                chan_3:> valdata3[k];
                clearbuf(chan_3);

               //here time is not enough for me to capture all data ,so the next channel is wrong.

                chan_4:> valdata4[k];
                clearbuf(chan_4);
                chan_5:> valdata5[k];

                clearbuf(chan_5);
                k++;
                break;//
         }

Here is some result : Channel 3 is right ,and the chan-4 is wrong .because I clearbuf one bit after sampling.
=============Channel 3==================

00010011010000111011010000001110

the channel : 3 , the volt is 2.166507
=============Channel 4==================


00000010000110111111111111101101
the channel : 4 , the volt is 2.166013
00101100100001110101110100001110
the channel : 4 , the volt is 4.213932


User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

Place your clearbuf for each port outside the case and test again. Post your results.
zhy44th
Member
Posts: 11
Joined: Mon Dec 18, 2017 9:58 am

Post by zhy44th »

the AD7768 signal is shown below:
Image

I plan to read the 32 buffered port data every time the DRDY signal rising ,without clearbuf after read ,the data will be wrong...if I clearbuf too late ,the MSB data may be cleared and i cannot get the right result.
I think the problem mostly troubled is : if when I read the port ,the clock goes on ,and change the later channel's data...
here is the code and result:

Code: Select all

select
            {
                case p_rd  when  pinsneq(0):> cmd:
                   chan_1:> valdata1[k];
                   //clearbuf(chan_1);
                   chan_2:> valdata2[k];
                   //clearbuf(chan_2);
                   chan_3:> valdata3[k];
                   //clearbuf(chan_3);
                   chan_4:> valdata4[k];
                   //clearbuf(chan_4);
                   chan_5:> valdata5[k];
                   //clearbuf(chan_5);
                   k++;
                break;//上升沿出现,读取数据,清除
            }
        }
        else
        {

            clearbuf(chan_1);
            clearbuf(chan_2);
            clearbuf(chan_3);
            clearbuf(chan_4);
            clearbuf(chan_5);

        }
the right data:
the channel : 3 , the volt is 1.809944
the capture bin:
10110001111100010001110011001000
the msbader val,after bitrev function:
00010011001110001000111110001101
the wrong data:
the channel : 2 , the volt is 3.298387
the capture val :
10011000110010001110011001000011
the msbader val,after bitrev function:
11000010011001110001001100011001
Another way:

Code: Select all

 select
            {
                case p_rd  when  pinsneq(0):> cmd:
                   chan_1:> valdata1[k];
                   clearbuf(chan_1);
                   chan_2:> valdata2[k];
                   clearbuf(chan_2);
                   chan_3:> valdata3[k];
                   clearbuf(chan_3);
                   chan_4:> valdata4[k];
                   clearbuf(chan_4);
                   chan_5:> valdata5[k];
                   clearbuf(chan_5);
                   k++;
                break;//上升沿出现,读取数据,清除
=============Channel 3==================

the channel : 3 , the volt is 1.811311
the capture bin:
10111110010110010001110011001000
the msbader val,after bitrev function:
00010011001110001001101001111101

=============Channel 4==================

the channel : 4 , the volt is 1.811847
the capture bin:
11100011011110010001110000101000
the msbader val,after bitrev function:
00010100001110001001111011000111

=============Channel 5==================

the channel : 5 , the volt is 1.811550
the capture bin:
11100110001110010001110010101000
the msbader val,after bitrev function:
00010101001110001001110001100111

=============Channel 6==================

the channel : 4 , the volt is 3.622458
the capture bin:
01010101110011001000111000110100
the msbader val,after bitrev function:
00101100011100010011001110101010

=============Channel 7==================

the channel : 6 , the volt is 3.622657
the capture bin:
10000010101011001000111001110100
the msbader val,after bitrev function:
00101110011100010011010101000001
it seems that I clear one bit, so the answer become twice.
zhy44th
Member
Posts: 11
Joined: Mon Dec 18, 2017 9:58 am

Post by zhy44th »

mon2 wrote:Place your clearbuf for each port outside the case and test again. Post your results.
if I clearbuf outside ,some useful data will be clear. Please look at my new post below.
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

Review the topic of "Synchronising clocked I/O on multiple ports", here:

https://www.xmos.com/published/xmos-pro ... =B&page=26

and post your results. The use of the sync feature may help.
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

Another suggestion is to consider to use the par construct to launch another thread (virtual CPU) to capture the data at the same time.

For example:

Code: Select all

par{

on tile[0]: sample_inputs_1_4();
on tile[0]: sample_inputs_5_8();
.
.
.
}
https://www.xmos.com/published/how-use- ... iple-tiles

http://www.xcore.com/viewtopic.php?t=3407
zhy44th
Member
Posts: 11
Joined: Mon Dec 18, 2017 9:58 am

Post by zhy44th »

mon2 wrote:Review the topic of "Synchronising clocked I/O on multiple ports", here:

https://www.xmos.com/published/xmos-pro ... =B&page=26

and post your results. The use of the sync feature may help.
Thank You.
I try to add the sync function,but the result change little

Code: Select all


    configure_clock_src(clk, p_clk_in);

    configure_in_port(p_rd, clk);

    configure_in_port(chan_1,clk);
    configure_in_port(chan_2,clk);
    configure_in_port(chan_3,clk);
    configure_in_port(chan_4,clk);
    configure_in_port(chan_5,clk);

     set_port_sample_delay(chan_1);
     set_port_sample_delay(chan_2);
     set_port_sample_delay(chan_3);
     set_port_sample_delay(chan_4);
     set_port_sample_delay(chan_5);
     set_port_sample_delay(p_rd);  

     sync(chan_1);
     sync(chan_2);
     sync(chan_3);
     sync(chan_4);
     sync(chan_5);


     start_clock(clk);

     clearbuf(chan_1);
     clearbuf(chan_2);
     clearbuf(chan_3);
     clearbuf(chan_4);
     clearbuf(chan_5);

    while(k<num)
    {
        p_rd :> cmd;
       
        if(cmd==0&&k==0)
        {   select
            {
                case p_rd  when  pinsneq(0):> cmd:

                clearbuf(chan_1);
                clearbuf(chan_2);
                clearbuf(chan_3);
                clearbuf(chan_4);
                clearbuf(chan_5);
                k++;
                break;            }

        }

        if(cmd==0&&k<num)
        {
            select
            {
                case p_rd  when  pinsneq(0):> cmd:


                   chan_1:> valdata1[k];
                   clearbuf(chan_1);
                   chan_2:> valdata2[k];
                   clearbuf(chan_2);
                   chan_3:> valdata3[k];
                   clearbuf(chan_3);
                   chan_4:> valdata4[k];
                   clearbuf(chan_4);
                   chan_5:> valdata5[k];
                   clearbuf(chan_5);

                   k++;
                break;//            }
        }

Here is some result .the red part is wrong:

=============Channel 3==================

the channel : 3 , the volt is 0.545241
the capture bin:
10110111100100001000100011001000
the msbader val,after bitrev function:
00010011000100010000100111101101

=============Channel 4==================

the channel : 4 , the volt is 0.545512
the capture bin:
10011000001100001000100000101000
the msbader val,after bitrev function:
00010100000100010000110000011001

=============Channel 5==================


the channel : 2 , the volt is 1.090783
the capture bin:
00100010011010000100010001010100
the msbader val,after bitrev function:
00101010001000100001011001000100

And I don't understand the clearbuf function ,I try to use it like this:

Code: Select all

         clearbuf(chan_1);                   
         chan_1:> valdata1[k];     
I can get the right data...so the:> function read the prevoius 32 bits data or the next 32 bits????

Can you give me some suggestions to capture the AD data?
Thank you very much.
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

Is your hardware port pin mapping locked down or are you flexible?

Some more ideas:

1) If ok to move to other pins, consider to make use of a complete set of buffered 8 bit port. Then map each bit of this port to your individual A/D. Now you can sample each bit on each clock cycle.

2) Try the following:

Merge the single 1 bit ports into a 8 bit port so you can perform a test.

Image

Code: Select all

//           on tile[0] : in buffered port:32 chan_3 = XS1_PORT_1M;
//           on tile[0] : in buffered port:32 chan_4 = XS1_PORT_1N;
//           on tile[0] : in buffered port:32 chan_5 = XS1_PORT_1O;
             
             on tile[0] : in buffered port:32 chan_3_5 = XS1_PORT_8D; // will allow for 4 samples (elements) of 8 bits in the buffer
Also do not believe it should be required to manually clear the buffer using clearbuf as this is done for you by the XMOS architecture. The use of clearbuf is also consuming time.

Image

Using the same h/w setup, you should be able to convert merge port_1M, port_1N, port_1O into a 8 bit port and attempt to sample these 3 bits in a single clock cycle.

The one small disadvantage of this method is that now you will have to split up the 8 bit value for your end app use but it is an idea worth testing.

That is, once you read the 3 bits using the 8 bit element, you will have to break down

8B0 back to your A/D #x
8B1 back to your A/D #x+1
8B2 back to your A/D #x+2

but if you can use a full 8 bits for all of your a/d mapping then it is worth the effort and can be done. Note again that you can sample 4 elements (ie. 4 clock cycles worth) before the FIFO is full. See if the results improve for these 3 bits and please post your results.
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

Try this idea and post your results:

Code: Select all

//port config:
           on tile[0] : clock clk = XS1_CLKBLK_1;
           on tile[0] : in port p_clk_in = XS1_PORT_1I;//using  external AD CLK
           on tile[0] : in port p_rd = XS1_PORT_1J;// DATA READY SIGNAL
           on tile[0] : in buffered port:32 chan_1 = XS1_PORT_1L;//DATA CHANNEL
           on tile[0] : in buffered port:32 chan_2 = XS1_PORT_1K;
           on tile[0] : in buffered port:32 chan_3 = XS1_PORT_1M;
           on tile[0] : in buffered port:32 chan_4 = XS1_PORT_1N;
           on tile[0] : in buffered port:32 chan_5 = XS1_PORT_1O;

...

          configure_clock_rate(clk, 100, 2); // can also try (clk, 100, 4) = 25 mhz

          set_port_inv(p_clk_in); // so we can sample when A/D clk is low


          // sample data when A/D clk is low (but p_clk_in must be high so we inverted above)  
          configure_in_port_strobed_slave(chan_1 , p_clk_in, clk);
          configure_in_port_strobed_slave(chan_2 , p_clk_in, clk);
          configure_in_port_strobed_slave(chan_3 , p_clk_in, clk);
          configure_in_port_strobed_slave(chan_4 , p_clk_in, clk);
          configure_in_port_strobed_slave(chan_5 , p_clk_in, clk);

          start_clock(clk);

          //wait for data ready signal which last about 40ns. it's not enough.

            select
            {
                case p_rd  when  pinsneq(0):> cmd:

                chan_1:> valdata1[k]; // you can add the clearbuf if required but it should be...
                chan_2:> valdata2[k];
                chan_3:> valdata3[k];
                chan_4:> valdata4[k];
                chan_5:> valdata5[k];

                k++;
                break;//
         }
zhy44th
Member
Posts: 11
Joined: Mon Dec 18, 2017 9:58 am

Post by zhy44th »

mon2 wrote:Try this idea and post your results:

Code: Select all

//port config:
           on tile[0] : clock clk = XS1_CLKBLK_1;
           on tile[0] : in port p_clk_in = XS1_PORT_1I;//using  external AD CLK
           on tile[0] : in port p_rd = XS1_PORT_1J;// DATA READY SIGNAL
           on tile[0] : in buffered port:32 chan_1 = XS1_PORT_1L;//DATA CHANNEL
           on tile[0] : in buffered port:32 chan_2 = XS1_PORT_1K;
           on tile[0] : in buffered port:32 chan_3 = XS1_PORT_1M;
           on tile[0] : in buffered port:32 chan_4 = XS1_PORT_1N;
           on tile[0] : in buffered port:32 chan_5 = XS1_PORT_1O;

...

          configure_clock_rate(clk, 100, 2); // can also try (clk, 100, 4) = 25 mhz

          set_port_inv(p_clk_in); // so we can sample when A/D clk is low


          // sample data when A/D clk is low (but p_clk_in must be high so we inverted above)  
          configure_in_port_strobed_slave(chan_1 , p_clk_in, clk);
          configure_in_port_strobed_slave(chan_2 , p_clk_in, clk);
          configure_in_port_strobed_slave(chan_3 , p_clk_in, clk);
          configure_in_port_strobed_slave(chan_4 , p_clk_in, clk);
          configure_in_port_strobed_slave(chan_5 , p_clk_in, clk);

          start_clock(clk);

          //wait for data ready signal which last about 40ns. it's not enough.

            select
            {
                case p_rd  when  pinsneq(0):> cmd:

                chan_1:> valdata1[k]; // you can add the clearbuf if required but it should be...
                chan_2:> valdata2[k];
                chan_3:> valdata3[k];
                chan_4:> valdata4[k];
                chan_5:> valdata5[k];

                k++;
                break;//
         }

Thank you.

I tried, but the result is not good. I think when the AD's clock is Low, the port samples data. But it may samples several same data for example :(0000) or(1111) in one AD cycle.
Here is the result:
the channel : 0 , the volt is 4.889709
the capture bin:
00110101101100110001100100000011
the msbader val,after bitrev function:
11000000100110001100110110101100
I'm going to change the AD's signal, cut the 32 bits to 28 bits.

Image

Thank you.
Post Reply