pythonpython-2.7synchronizationraspberry-piclock-synchronization

How to sync the clocks in Raspberry Pi?


I'm new to raspberry pi, trying to send a stream of bits from sender to receiver. However bits are not received in correct pattern most of the times, they seems to be shifted a little. I think i'm unable to synchronize them properly. Does anyone how I can sync the clocks

Python Code is here

# Sender
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.OUT)
while True:
  GPIO.output(23, GPIO.HIGH)
  time.sleep(1)
  GPIO.output(23, GPIO.LOW)
  time.sleep(1)
  # .... some more bits here

# Receiver
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)
while True:
   bit = GPIO.input(17)
   print bit
   time.sleep(1)

Solution

  • You should not try to synchronize the sender and the receiver based on time. You should choose the frequency of sending on the sender side, and let receiver just sit there and wait for the bits to come, without sleeping. Because sleeping makes you miss stuff.

    Use:

    GPIO.add_event_detect(17, GPIO.BOTH, callback=my_callback)
    

    to listen to a change on the PIN, and execute my_callaback when it happens. You can also choose to wait for rising edge via GPIO.RISING or the falling via GPIO.FALLING.

    For your example, here is something to start with, not tested or anything:

    import RPi.GPIO as GPIO  
    from time import sleep     
    
    GPIO.setmode(GPIO.BCM)     
    GPIO.setup(17, GPIO.IN)    
    
    def readbit(channel):  
        bit = GPIO.input(17)
        print bit
    
    GPIO.add_event_detect(17, GPIO.BOTH, callback=readbit)  
    
    while True:
        sleep(1)  # do something useful here
    

    This probably won't be enough, since you can't detect bits that don't change the state. To tackle this, you have quite a few options, and I will only mention two most simple ones:

    Control signal

    You can use another PIN as a control signal, and use it to trigger the reads on the receiver. This way, you trigger the read on the rising edge of the control pin, and read the value of the data pin.

    On the sender:

    def send_bit(pin, bit):
        GPIO.output(24, GPIO.HIGH)  # first send the control bit 
        GPIO.output(pin, bit):  # then the data on another pin
    
    while True:
      send_bit(23, GPIO.HIGH)
      time.sleep(1)
      send_bit(23, GPIO.LOW)
      time.sleep(1)
    

    On the receiver:

    DATA_PIN = 17
    CONTROL_PIN = 18  # or whatever
    def readbit(channel):
        bit = GPIO.input(DATA_PIN)
        print bit
    GPIO.add_event_detect(CONTROL_PIN, GPIO.RISING, callback=readbit)
    

    One wire protocol

    Another solution, if you don't want to use two wires, is to create a simple protocol. For example:

    This might be complicated, but it actually isn't. All you need to do now is to trigger the reading on the rising edge, and read the data somewhere between 0.1 and 0.9 seconds after that. Let's make it 0.5 seconds, to be sure we are in the middle of this time.

    On the sender:

    def send_bit(pin, bit):
        GPIO.output(pin, GPIO.HIGH)  # send the control bit first, always HIGH
        GPIO.output(pin, bit)  # send the actual data bit
    
    while True:
      send_bit(23, GPIO.HIGH)
      time.sleep(1)
      send_bit(23, GPIO.LOW)
      time.sleep(1)
      # .... some more bits here
    

    On the receiver:

    def readbit(channel):
        time.sleep(0.5)  # waiting to be in the safe time for read
        bit = GPIO.input(17)
        print bit
    GPIO.add_event_detect(17, GPIO.RISING, callback=readbit)