2
\$\begingroup\$

enter image description here

Hello, I want to design a blinking LED module that can run stand-alone, but also synchronize with other identical modules over a single shared SYNC wire.

The behavior I’m trying to achieve is:

Each module has its own local oscillator that drives LEDs at about 0.7 Hz (≈1.4 s period).

When running alone, the module just uses this local 0.7 Hz oscillator to blink.

All modules are connected to a common SYNC line:

Each module should output a short pulse (around 10–20 ms) once per 0.7 Hz cycle on this SYNC line.

At the same time, each module should monitor the SYNC line.

If a module detects pulses from another module, it should phase-lock its own 0.7 Hz oscillator to those pulses, so that all modules end up blinking in sync.

There is no fixed master: whichever module happens to lead can temporarily act as the timing reference, and the others should follow. If that “master” disappears (powered off or disconnected), the remaining modules should continue blinking using their own oscillators (and re-establish sync among themselves).

The SYNC line is a single wire with a pull-up; each module needs to be able to both pull it low to generate a pulse and sense pulses generated by others.

What kind of circuit topology , synchronization scheme or IC is suitable for this?

How can I implement:

a local ~0.7 Hz oscillator, and

a mechanism to reset/adjust its phase based on pulses seen on the SYNC line, so that multiple modules converge to synchronized blinking?

A solution using discrete logic / op-amps / comparators or a small microcontroller is fine; I’m mainly interested in the synchronization method (e.g., edge-triggered reset, simple PLL-like scheme, monostable + RC oscillator alignment, etc.) and how to avoid bus contention on the single SYNC wire.

\$\endgroup\$
8
  • \$\begingroup\$ You should work the specification out for yourself. You have to consider the worst case start-up condition where fresh power is applied to a bunch of modules and, design a mechanism where one can force itself to be master and all the others respect that. You must figure that out first then consider how it is to be implemented. Of course, if you believe a solution already exists then you are asking a veiled product recommendation question so, be aware of that. Alternatively just have a small "fixed master" that does nothing except provide sync pulses. \$\endgroup\$ Commented 2 days ago
  • 1
    \$\begingroup\$ How many modules you intend to have together in maximum? Do they share a power supply/ground, or are they isolated? If isolated, one wire cannot convey any data between modules, two are required. \$\endgroup\$ Commented 2 days ago
  • 1
    \$\begingroup\$ @mete5050 nothing about that requires any custom silicon \$\endgroup\$ Commented 2 days ago
  • 1
    \$\begingroup\$ Don't think in terms of denoting a "master" device; instead, think in terms of reaching a consensus among peers. There are plenty of "firefly" projects on the interwebs in which independent nodes both flash and detect the flashes of others to eventually all flash together. It's actually a fairly simple algorithm. \$\endgroup\$ Commented 2 days ago
  • 1
    \$\begingroup\$ How close does the timing synchronization need to be? 1ns, 1us, 1ms, 10ms? \$\endgroup\$ Commented 2 days ago

6 Answers 6

6
\$\begingroup\$

If you don't want to bother with programming a micro for each unit, below is the schematic of a relatively simple circuit using a 555 timer configured as a self-synchronized astable multivibrator:

The Sync-signal short negative-going-pulse is generated at each oscillator's transistor collector by the associated RC differentiating circuit from the rising edge of the 555 output square-wave.
They are then all wire-OR'd together by the Sync line.
The negative pulse triggers the 555's TRIG input, which means the first oscillator output to go high triggers all the others to start also, so the operating frequency is determined by the oscillator that has the highest frequency (frequency difference due to usual component tolerances).

It can be expanded to an arbitrary number of oscillators by just connecting the Sync signal to the added units.
The addition or subtraction of oscillator circuits thus has no significant effect on the rest of the oscillators' operation.

The "Out" signals are the outputs to the LED driver.

Note in the LTspice sim for two 555 oscillators, that Out2 has a slightly longer on-time than Out1 due to its higher timing capacitor value (for simulation purposes), but its period is synced to Out1.

enter image description here

\$\endgroup\$
7
\$\begingroup\$

I'll adopt mostly from Marcus' answer, but I think that randomized startup delay isn't necessary with proper bus topology. In general, I hesitate to connect multiple push-pull devices in parallel, as any deviation from the protocol could result in two microcontrollers shorting through.

The SYNC bus should be open-drain active-low with a pullup resistor. Each device should maintain a 0.7Hz clock and output a 10ms pulse when the timer resets. The most important part is the edge at the beginning of the pulse. Have the device interrupt on the falling edge (the beginning of the pulse, as it is active-low) and, if it is not currently also emitting a pulse, reset it's own timer to zero.

If you want devices to join the bus gracefully when turned on, have a 1.5 second delay on startup to sync with any existing devices on the bus - not mandatory though. If you want devices to join the bus gracefully after already being turned on, this isn't possible - imagine the case where two devices, out of sync, are connected to each other. One of them is going to need to make an abrupt change.

If you turn on all of the devices at once: they will start in sync, and remain in sync.

While in sync, if one runs slightly faster than the other, then it will be the first one to pull the bus low, and it will cause all of the other devices to reset their timer slightly earlier than they would have otherwise. This is what keeps them in sync.

If you connect a device to an existing network: the interrupt will trigger within the first 1500ms and then the device will immediately be in sync with the rest of the devices

If you have an existing network, and you remove a device, it doesn't matter - each device maintains and follows its own internal clock by default, except when preempted by another device.

e

The green lines here denote when each device starts, and the red line is the SYNC bus. You can see that for the first reset of the timer, device 1 doesn't do anything. It then starts outputting pulses on the resets. These pulses reset device two, which turns on halfway out of phase. Once device two resets its timer, it's in sync

\$\endgroup\$
5
\$\begingroup\$

A solution using discrete logic / op-amps / comparators or a small microcontroller is fine

sounds like a quick job for a microcontroller. They come with integrated oscillators, or can use an external quartz resonator (jellybean parts, think cents, each for the microcontroller and the quartz).

Deriving a T=1/f=1/0.7 s period from that is trivial – in fact, even low-cost entry-level Cortex-M0-based MCUs these days have a 32 bit timer that could directly be used to turn on an LED for a defined time every T.

The synchronization is trivial: your microcontroller powers on. It listens on the shared line for T + some positive random amount of milliseconds, and

  • if no pulse occurs in that time, it enables and starts the blink timer to blink immediately and output a pulse (and repeat every T later again)
  • If there is a pulse in that time, it sets the timer to blink immediately (and every T later again)

There's no need to steer any phase – all you want is synchronicity, and that can be done with a "first to output a pulse wins all others". Since you re-arm the timer any time an external pulse comes in, you inherently synchronize to the master's clock frequency, and only if the master fails, you would need your own clock.

Because your time periods are unbelievably long in MCU terms and "blinking an LED" is still very very long, this is really something trivially implementable as software – really just an interrupt handler for your timer unit, and during the acquisition phase an edge trigger on the sync line (but that's already not necessary – simply polling that pin would suffice).

(There's an infinite numbers of doing this in other ways, to higher precisions, with less bandwidth, lower jitter… But you don't need any of that.)

\$\endgroup\$
3
  • \$\begingroup\$ And the solution to the elephant in the room (cold start with multiple connected devices) might be.....? \$\endgroup\$ Commented 2 days ago
  • \$\begingroup\$ @Andyaka haha! The random positive delay after a self-measured T! That solves the simultaneous power-on conflict, and the first one whose random timer runs out becomes master. \$\endgroup\$ Commented 2 days ago
  • \$\begingroup\$ (if two clocks randomly end up being so synchronous that they coincide more closely than can be detected, no harm done, they virtually form one master clock. If one drifts and becomes a bit earlier than the other, it becomes the master, because the earlier edge starts triggering the slaves) \$\endgroup\$ Commented 2 days ago
3
\$\begingroup\$

Assuming you can live with ± 32us of timing uncertainty, then...

Take a small microcontroller like...
ATTINY10-TSHR
$0.35 each.
running code similar to the following.

#define COUNT_PERIOD (437500) //1.4s #define SYNC_PERIOD (312) //10ms sync pulse //Macros defining SYNC pin #define SYNC_PIN_MASK (0x01) #define EANBLE_SYNC_PIN_PULLUP (PUEB |= SYNC_PIN_MASK) #define GET_SYNC_PIN (PINB & SYNC_PIN_MASK) #define CLR_SYNC_PIN PORTB &= ~SYNC_PIN_MASK #define SET_SYNC_PIN_TO_INPUT DDRB |= SYNC_PIN_MASK #define SET_SYNC_PIN_TO_OUTPUT DDRB &= ~SYNC_PIN_MASK uint32_t count; void main(void){ //Use C8MHz ± 1% internal oscillator for CPU clock. CLKMSR = 0; //write oscillator calibration to get 1% accuracy. OSCCAL = USER_CALIBRATION_VALUE; //Use 1.0 clock prescaler CLKPSR = 0; //Set timer for normal mode TCCR0A = 0; //Use 256:1 prescaler on timer (32us per count) TCCR0B = 4; TCCR0C = 0; //Enable pullup on SYNC pin EANBLE_SYNC_PIN_PULLUP; //Set SYNC_PIN CLR_SYNC_PIN; while(1){ SET_SYNC_PIN_TO_OUTPUT; //Output 10ms sync pulse. TCNT0 = 0; while(TCNT0 < SYNC_PERIOD); //Wait for sync pin to go inactive. SET_SYNC_PIN_TO_INPUT while(SYNC_PIN == 0); // ...Do something here for your lights. //Wait for 1.4 second period to run out or sync pulse to come in. //Whichever device has the fastest clock will set the period for //all other devices. TCNT0 = 0; while(TCNT0 < COUNT_PERIOD && SYNC_PIN == 1); // ...Do something here for your lights. }//end while } 

Essentially just user the internal 8MHz oscillator and internal timer hardware to time out a 10ms and 1.4s pulse while also watching for SYNC pulses from the other modules. You can use the internal pullup resistor on the MCU IO pin to save space/cost. Timing accuracy would be about 1% assuming you calibrate the internal oscillator using the OSCCAL register.

\$\endgroup\$
2
\$\begingroup\$

The top multivibrator uses a 10uF caps for the timing. The bottom one uses a 11uF caps so its period is a bit longer. Once you involve a synchronisation using short Synch1 and Synch2 pulses after every half-period the both multivibrators runs synchronously:

enter image description here

The green waveform is the output of top multivibrator, the blue is the output of bottom multivibrator:

Without synchronisation: enter image description here

With synchronisation: enter image description here

By using some multiplex technique like positive-negative pulses etc.. it can be done with single wire(not a two wire).

\$\endgroup\$
0
\$\begingroup\$

The least-cost and dodgy version would be that if you are using NE555 type timers, simply connect a wire from the timing capacitor in each timer circuit to the sync line.. Every time you add a flasher, you increase the current feeding the capacitor by one unit and increase the capacitance by one unit. So they all flash at the same rate because N flashers have N times the current and N times the capacitance.

\$\endgroup\$
2
  • \$\begingroup\$ Found the "dodgy" flaw in just connecting all the timing capacitors together. It only works if all the 555's have identical trigger voltages (and of course in real life they don't). Any deviation in those voltages means that not all will trigger at the same time, so they will end up latched in either an ON or OFF state. \$\endgroup\$ Commented yesterday
  • \$\begingroup\$ Good point, some of the timers will get stuck . \$\endgroup\$ Commented 5 mins ago

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.