NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Syncing up 2 or more microcontrollers

January 15, 2013
by scootergarrett
scootergarrett's Avatar

Here is an interesting problem with probably many solutions, I would like to open up for ideas. Say I had 2 identical independent sensors/microprocessors units, and I wanted them both to take data starting at the same time, so they could be compared without having to post process sync data. Easiest way would just to turn them on at the same time, but I’m thinking the activation time might vary too much, and this is just too simple. So I was thinking have a master and slave sensors, which would be connected temporarily then a signal would be sent and all the sensors would start. Sound feasible/ any other ideas?

I’m looking to sample at 400Hz to give an idea of the time accuracy I’m thinking of

January 15, 2013
by Ralphxyz
Ralphxyz's Avatar

Hi scootergarrett, now I've actually thought about doing something like this before but ended up realizing that I really could not detect what was not simultaneous actions with a 14.7456 clock tick and then I could go to 16 mhz or even 20 mhz with the ATmega 168 or 328 processor. At 400Hz you would get over 3,000 cycles a second is your perception faster than that?

That aside lets think about this. You can simultaneously change 8 pins at a time by simply addressing a port so you could theoretically turn two (8) sensors on at the same time.

Ralph

January 15, 2013
by JimFrederickson
JimFrederickson's Avatar

It is often customary in Critical Industrial Control Applications to have multiple sensors subsystems reporting results. Many systems even implement a "voting scheme" in order to protect against bad measurements.

Personally, in your case, I would just have the sensor take it's measurements continuously, and process the results using averaging and a maximum delta/change rate.

Then you could use and I2C implementation, or a 3-wire Communications Implementation, to send the results on demand.

The I2C Standard already supports "multi-drop"/"multiple device on a bus" at one time.

A 3-wire implementation is "point-to-point", but it is not too hard to make a Master to to use a "token-ring scheme" or to have multiple 3-wire buses from a Master to communicate to multiple devices. (Usually a 3-wire bus will use a "device select line" to select a device tied to a common bus.)

If you really need to have measurements that are as "close to simultaneous as possible" then you can tie the sensor subsystems to a "trigger I/O" that the Master would assert when a measurement is desired. Then you can use the chosen communications bus to gather the results. From what you have described so far, I wouldn't think this would be necessary for what you want to accomplish.

January 15, 2013
by scootergarrett
scootergarrett's Avatar

Ok this is what I got so far 2 chips (but could just as easily be 5) connected, as shown here. The primary chip sends a low command on PC4 then starts normal code while the secondary chip(s) wait for PC4 to go low then start normal code. The 'normal' code I have is just blinking LED's so I need a 2 channel scope to test this (which I will to tomorrow) to see if they are out of phase. Anyways after the normal code is going the chips can be disconnected from each other. To keep from having to pull the serial cable wires and navigate to a different directory with command prompt I made a variable 'primary' that controlled which code was run.

// for NerdKits with ATmega328p
// for syncing up two chips that then can be taken apart from one another

#define F_CPU 14745600

#include <stdio.h>
#include <math.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/io_328p.h"
#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include "../libnerdkits/uart.h"

/// Change this between loading chips ///
#define primary 1            // change this between loading chips easy way to not
                                // have to bounce around with the command prompt
#define SampleDelayTime 20 // ms between samples

int main()
{
    DDRC |= (1<<PC3);               // Make PC3 an output for testing

    if(primary)
    {   // this estup/sync code for primary chip
        DDRC |= (1<<PC4);           // Make PC4 an output
        PORTC  |= (1<<PC4);         // Turn on PC4
        delay_ms(3000);             // Give some time to balance out
        PORTC  &= ~(1<<PC4);        // turn off PC4
    }
    else
    {   // this setup/sync code for slave chip
        DDRC &= ~(1<<PC4);          // Set pin PC4 as input
        PORTC |= (1<<PC4);          // Turn on PC4 pull up resistor
        delay_ms(1500);             // Give some time to balance out
        while((PINC & (1<<PC4)) != 0);
    }

    /// Normal synced code here ///

    while(1)
    {   // Synced portion of code for sampling (oscilloscope)
        PORTC  |= (1<<PC3);
        delay_ms(SampleDelayTime);
        PORTC  &= ~(1<<PC3);
        delay_ms(SampleDelayTime);
    }

    while(1);
    return 0;
}
January 16, 2013
by scootergarrett
scootergarrett's Avatar

Well somehow I ended up with 2 slightly different crystal oscillators (14.7456N and F14.74P), so after running the code for a while they drift apart as expected, but I was able to measure the first cycles of the 'normal' code and there was no measurable phase difference (measuring at 0.065ms per sample). So 400Hz should be fine. close up of scope output

January 16, 2013
by JimFrederickson
JimFrederickson's Avatar

Scooter,

There are, as you have discovered, numerous issues that can cause a differences between timing of microcontrollers. (Type of clock, quality of any and all parts involved, variances in solder joints, operating temperature and temperature variances, power fluctuation, etc...)

With separate systems/subsystems that are not connected it would be impossible for you/I/us to get 100% synchonization through a practical method. (In fact even test equipment has "acceptable skew"/"tolerance" even when on a single board/subsystem.)

Pretty much all things are built to operate "within tolerances", which is basically "allowable differences".

So what is your "tolerance" going to be?

You can do a "simple adjustment for "drift", as you phrased it, that will get you a little closer to 100%.

Do the following:

1 - Attach a "sequence number" for every sample taken and in your
    "sample data" have "samples" and "synchronization tags".
    (The "sequence number" should be large enough to 
    cover the entire range of samples for the time
    in question.)
2 - Once you have "started your subsystems and synchronized them" you 
    can set them apart for your sampling.
3 - Once your sampling period has expired, bring the subsystems back
    together re-attach them "re-synchronize" them.
    Saving a "synchronization tag" in your "sample data".
4 - Now you can either stop the sampling or put them back to collect
    more samples.

(Note, if you have more than a single subsystem then you would need to connect them all together before resynchronizing them. If you did it individually your "post-processing" would have to take into account the "Master" will have a "synchronization tag" for each slave and each slave will only have it's own "synchronization tag".)

Now your "sample data" will have "samples" and "synchronization tags".

Comparing the "synchronization tags" in a "slave subsystem" to the appropriate "synchronization tag" in your "Master subsystem" will tell you "how far off and in what direction off" the subsystems are.

Now this won't account for "all of the drift possibilities", but it would get you a little closer. If you did this over several "sample sessions", and if the differences between the Master and any particular slave subsystem remained somewhat consistent you can be more assured of the accuracy.

But again...
What are "your tolerances" going to be?

Another change needs to be made as well...

The current synchronization method will not work.

Breaking apart a common GND, if your subsystems are battery powered, is unlikely to disturb processing too much. (With the assumption that both batteries are very similar and charged to a similar level. Although it likely will have some affect.) Now reconnecting them" will likely have a much greater affect.

(The assumption here, is that you said you didn't want wires to connect sampling subsystems, so I am thinking that may very well apply to "power connections". Hence, the assumption of "battery power".)

Most likely the best method would be to use and IR LED and IR Phototransister pair to transfer/detect the synchronization signal between your subsystems.

That way there doesn't need to be an electrical connection.
(Additionally have a button/switch on the slave to tell it when to begin looking for the synchronization signal may be helpful too, or make the signal more complex so there are less changes of a "false trigger".)

January 16, 2013
by pcbolt
pcbolt's Avatar

@ scootergarret

Another possibility you could try is to calibrate your MCU's ahead of time. Arbitrarily assign one MCU/clock as "right" and the other as "wrong". Then you could setup an identical interrupt driven timing program on each system to measure the "drift". Once you deploy the "wrong" system in the wild, you can compensate along the way. You could even extend the scenario to compensate for temperature differences if the MCU's are connected while in different environments during the calibration process.

Post a Reply

Please log in to post a reply.

Did you know that reading a double floating point variable with scanf requires "%lf" for "long float"? Learn more...