STARTkit and external clock Topic is solved

All technical discussions and projects around startKIT
dsdanielko
Active Member
Posts: 33
Joined: Sat Mar 12, 2016 3:12 pm

STARTkit and external clock

Post by dsdanielko »

Is it possible to set the reference clock with an external clock on this board?

If it is not, are there any development boards that does have this feature?

I am trying to run multiple boards off of a single external clock to keep them perfectly synchronised.

Thanks


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

Post by mon2 »

Yes, this is possible. Being an external clock, you must connect your external clock source (3V3 max voltage swing to remain compliant with the I/O voltage swing of the XMOS device) to a SINGLE BIT port.

See here for full details and example on how to map an external clock source:

https://www.xmos.com/published/xc-clock ... and-output


This PDF document is more detailed than the webpage:

https://www.xmos.com/download/private/X ... 1.0%29.pdf
dsdanielko
Active Member
Posts: 33
Joined: Sat Mar 12, 2016 3:12 pm

Post by dsdanielko »

Can I divide the external clock to configure the clock blocks?
Going through <xs1.h>, it seems very ambiguous.

EDIT: I'm almost certain that you can't use the method that you posted after looking through xs1.h
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

According to the comment here by Snowman, no you cannot divide down an external clock source:

http://www.xcore.com/forum/viewtopic.php?t=540
Only internal clock can be divided down. You cannot divide down an external clock.
Here is some code on how to use an external port pin (single bit) with an external clock:

http://www.xmos.com/download/private/XS ... 73A%29.pdf
* see page 4 & 5 for details of the code

Do you wish to experiment with a specific clock source with your code ?

Consider to use the very nice SiLabs Si5351A PLL:

https://www.adafruit.com/product/2045

In the past week, we have taken this same demo board and programmed a low cost FPGA and another ultra low cost micro to allow us to generate any clock value on demand. Should be very simple to do the same using XMOS.

The noted PLL is I2C based (also known as SMBUS) -> respectively take any 2 single port bits on the StartKit and apply local pull-ups as required by the I2C spec. Use these port pins to program the ref board and feed the output of the PLL board into any free single port bit.

The PLL is dirt cheap (< $ 1 USD in low qty) and well worth the investment if you are not sure on the target external clock value. Use the SiLabs tool for Windows to generate the register values. We did the same for about a dozen values and each was spot on accurate.

Time permitting, can review coding up a small routine to use the same target PLL.

Also, there is an UART Slice board by XMOS (intended for use with their XS1 Slice Board) which features an onboard external clock source of 1.8432 Mhz. This is a common value used to accurately frame UARTs at PC standard baud rates. You may want to review that code to gain knowledge on how they apply this external clock source.

Varying with how many StartKits you plan to use, more focus should be on the signal integrity between the mated StartKit external clocks. That is, you are limited to the cable lengths that will carry this external clock.

How many StartKits will be used in this project ?
User avatar
infiniteimprobability
XCore Legend
Posts: 1126
Joined: Thu May 27, 2010 10:08 am
Contact:

Post by infiniteimprobability »

Only internal clock can be divided down. You cannot divide down an external clock.
This was true with XS1 but xCORE200 now has this feature:

Code: Select all

#if defined(__XS2A__)
/**
 * Configures a clock to use a 1-bit port as its source with a divide. If divide
 * is set to zero the 1-bit port provides the clock signal for the clock block
 * directly. If divide is non zero the clock signal provided by the 1-bit port
 * is divided by 2 * \a divide. This function is only available on XS2 devices.
 *  If the port is not a 1-bit port, an exception is raised.
 *  \param clk The clock to configure.
 *  \param p The 1-bit port to use as the clock source.
 *  \sa configure_clock_ref
 *  \sa configure_clock_xcore
 *  \sa configure_clock_rate
 *  \sa configure_clock_rate_at_least
 *  \sa configure_clock_rate_at_most
 */
void configure_clock_src_divide(clock clk, void port p, unsigned char d);
#endif
I'm not sure if the OP means synch the core clock specifically? Of course this is not necessary as you could have timer or I/O port synchronisation of task (Ie. they block until an event fires, which could be a timer clocked off the same ext clock or a shared I/O pin). I guess it depends what level of synchronisation is needed.. Should be possible to get close to 2ns..


EDIT.
Note that you are using startkit which has the XS1 so no external clock divider possible.. Sorry!
You can of course divide using another port, a task and clock block..

If you have a buffered output port (clocked from the external input clock) which constantly outputs 0xAAAAAAAA then you will get a divide by 2. You could change it to 0xCCCCCCCC to divide by 4 etc.. It's quite wasteful of a core, but may get you what you want.

The I2S component uses this trick to get the BCLK from MCLK.. See this diagram for the general idea.
Attachments
Screen Shot 2016-05-31 at 12.46.10.png
(162.79 KiB) Not downloaded yet
Screen Shot 2016-05-31 at 12.46.10.png
(162.79 KiB) Not downloaded yet
dsdanielko
Active Member
Posts: 33
Joined: Sat Mar 12, 2016 3:12 pm

Post by dsdanielko »

What I am trying to achieve is to have 32 startkits drive 1s and 0s out a port at exactly the same time (2ns is alright). The frequency at which 1s and 0s are output has to be variable and so does the phase of 1s and 0s between each startkit (so a startkit could be driving a 0 while another startkit is driving a 1). The requirement being they are all operating at the same clock edges.

I was thinking maybe I could do this by having the startkits communicate to one another to synchronise instead of using a common external clock, although the latter solution is ideal.

Thanks for the help so far!
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

If you have a buffered output port (clocked from the external input clock) which constantly outputs 0xAAAAAAAA then you will get a divide by 2. You could change it to 0xCCCCCCCC to divide by 4 etc.. It's quite wasteful of a core, but may get you what you want.
Now that is a clever idea !! Will have to keep this in mind as a cost savings.

32 StartKits = lots of cabling so the clock interface needs attention.

What is the max clock rate you anticipate to use ?

You could consider perhaps a RS485 or RS422 transceiver. Drive a RS485 / RS422 transmitter with your external clock (Intersil / Maxim / Exar have some that can support 20 to 40 Mbps @ 3v3 operation) and then a local RS485 / RS422 receiver at each StartKit with 100 to 120 ohm termination on the local receiver. This method will allow you to drive longer cables sending your clock with signal integrity. Pick a transceiver with 1/8th impedance and you could even use for 32+ StartKits. The transmitter will be fixed ON (enabled) and so will each local StartKit's RS485 receiver -> relationship is clock fanout with 1 transmitter to 32 StartKit receivers.

There may be other methods such as the use of true clock drivers / fanout buffers but this should work if you are wanting to trigger off clock edges. Otherwise, a CMOS oscillator on its own will not be able to drive so many loads (32 kits) without external component support.

How will you be interconnecting the StartKits ?
dsdanielko
Active Member
Posts: 33
Joined: Sat Mar 12, 2016 3:12 pm

Post by dsdanielko »

I would really like to limit the amount of any external components I add. This project will be soon passed onto someone else with even less programming knowledge than me haha. The startkits are currently not connected to each other at all. I was hoping just having an external clock that drives all the startkits would be enough to sync them.

I did find this: https://www.xmos.com/download/private/A ... rc1%29.pdf

If I used the general purpose slicekit (which has a XS1 - L silicon) could I change the ref clock to follow the external clock? That would solve my problems.
User avatar
infiniteimprobability
XCore Legend
Posts: 1126
Joined: Thu May 27, 2010 10:08 am
Contact:

Post by infiniteimprobability »

could I change the ref clock to follow the external clock?
Hi, I think that app note is not what you need - there is no need to slow down the CPU in your case. The XMOS chips have a core clock (processor clock) but in addition support up to 5 user clocks which can be used to control the rate of timers and ports. Because timers and ports can pause CPU execution at specific points, it means that the external clock can accurately control program execution - use the same external clock and you can ensure you have multiple chips running in a precisely synchronised manner.

XMOS devices are kind of a halfway house between a processor and an FPGA in this respect.. (we even have a cycle accurate simulator with waveform viewer...) It sounds like XMOS devices are exactly what you need but I recommend you reading the first 6 pages of this to see what I mean :

https://www.xmos.com/download/private/I ... 2738B).pdf

Maybe if you describe what it is you need to produce, I could write a small demo program to show you how it works...
User avatar
infiniteimprobability
XCore Legend
Posts: 1126
Joined: Thu May 27, 2010 10:08 am
Contact:

Post by infiniteimprobability »

Thought I would just put an example together..

So we have 3 tasks - they happen to be running on the same chip here, but in three different cores in parallel. Could just as easily be 3 different chips - makes no difference. Could also be any number of slaves, given the hardware constraints of driving signals that mon2 mentioned.

There is one master - has a port output and and synch out
Two slaves - port output and a synch in.

The synch out is looped backed to the synch inputs inside the simulator - ie. your clock wire in real life. I have chosen ports that come out on the STARTKIT so you can try this with wires and a scope/logic analyser.

Each task outputs 8, 9, 10... on a 4b port each time it sees a falling edge.

Each of the outputs is synchronised to the master strobe using a clock block driven by the synch line on a 1b port..

You can see on the waveform trace that things are pretty well aligned. There is a small lag for the slaves, but you could add a delay in the master or use a master that outputs nothing and a slave on the master startkit to compensate for this.
Just for educational purposes, I showed the 'core waiting' signal for each task. You can see when the processor is blocked waiting for something to happen. As soon as the falling edge comes, they all start together. Nice!

Also included is an extreme close up on a nanosecond scale.

Here is the code - you can see it's pretty simple. Also attached is IDE project.

Code: Select all

#include <xs1.h>

#define INITIAL_VALUE  0               //Port initial value

out port p_out_master = XS1_PORT_4E;   //Master output
out port p_synch_master = XS1_PORT_1J; //Master sync out
clock clk_master = XS1_CLKBLK_1;       //Master clock block

out port p_out_slave_0 = XS1_PORT_4C;  //Slave output
in port p_synch_slave_0 = XS1_PORT_1F; //Slave sync in
clock clk_slave_0 = XS1_CLKBLK_2;      //Slave clock block


out port p_out_slave_1 = XS1_PORT_4D;  //Slave output
in port p_synch_slave_1 = XS1_PORT_1G; //Slave sync in
clock clk_slave_1 = XS1_CLKBLK_3;      //Slave clock block


void master_gen(out port p_out, out port p_synch, clock clk){
    configure_clock_src(clk, p_synch);              //Clock block drives from synch port
    configure_out_port(p_out, clk, INITIAL_VALUE);  //Output clock by clockblock
    start_clock(clk);
    int count = 0x8;
    for(int i=0; i<4; i++){
        p_out <: count;             //This will not block becuase we have a port buffer
        delay_microseconds(1);
        p_synch <: 1;
        delay_microseconds(1);
        p_synch <: 0;               //Port output is triggered on falling edge
        count++;
    }
}

void slave_gen(out port p_out, in port p_synch, clock clk){
    configure_clock_src(clk, p_synch);              //Clock block drives from synch port
    configure_out_port(p_out, clk, INITIAL_VALUE);  //Output clock by clockblock
    start_clock(clk);
    int count = 0x8;
    while(1){
        p_out <: count; //This will block/only happen when a clock is received on synch
        count++;
    }
}

int main(void){
    par{
        master_gen(p_out_master, p_synch_master, clk_master);
        slave_gen(p_out_slave_0, p_synch_slave_0, clk_slave_0);
        slave_gen(p_out_slave_1, p_synch_slave_1, clk_slave_1);
    }
    return (0);
}
Attachments
synch_ports.zip
(47.5 KiB) Downloaded 526 times
synch_ports.zip
(47.5 KiB) Downloaded 526 times
Screen Shot 2016-06-01 at 09.02.32.png
(158.63 KiB) Not downloaded yet
Screen Shot 2016-06-01 at 09.02.32.png
(158.63 KiB) Not downloaded yet
Screen Shot 2016-06-01 at 08.52.44.png
(167.59 KiB) Not downloaded yet
Screen Shot 2016-06-01 at 08.52.44.png
(167.59 KiB) Not downloaded yet
Post Reply