Source code for usbcore.rx.clock

#!/usr/bin/env python3

from migen import *
from migen.genlib import cdc

from ..test.common import BaseUsbTestCase
import unittest


[docs]class RxClockDataRecovery(Module): """RX Clock Data Recovery module. RxClockDataRecovery synchronizes the USB differential pair with the FPGAs clocks, de-glitches the differential pair, and recovers the incoming clock and data. Clock Domain ------------ usb_48 : 48MHz Input Ports ----------- Input ports are passed in via the constructor. usbp_raw : Signal(1) Raw USB+ input from the FPGA IOs, no need to synchronize. usbn_raw : Signal(1) Raw USB- input from the FPGA IOs, no need to synchronize. Output Ports ------------ Output ports are data members of the module. All output ports are flopped. The line_state_dj/dk/se0/se1 outputs are 1-hot encoded. line_state_valid : Signal(1) Asserted for one clock when the output line state is ready to be sampled. line_state_dj : Signal(1) Represents Full Speed J-state on the incoming USB data pair. Qualify with line_state_valid. line_state_dk : Signal(1) Represents Full Speed K-state on the incoming USB data pair. Qualify with line_state_valid. line_state_se0 : Signal(1) Represents SE0 on the incoming USB data pair. Qualify with line_state_valid. line_state_se1 : Signal(1) Represents SE1 on the incoming USB data pair. Qualify with line_state_valid. """ def __init__(self, usbp_raw, usbn_raw): if False: ####################################################################### # Synchronize raw USB signals # # We need to synchronize the raw USB signals with the usb_48 clock # domain. MultiReg implements a multi-stage shift register that takes # care of this for us. Without MultiReg we would have metastability # issues. # usbp = Signal(reset=1) usbn = Signal() self.specials += cdc.MultiReg(usbp_raw, usbp, n=1, reset=1) self.specials += cdc.MultiReg(usbn_raw, usbn, n=1) else: # Leave raw USB signals meta-stable. The synchronizer should clean # them up. usbp = usbp_raw usbn = usbn_raw ####################################################################### # Line State Recovery State Machine # # The receive path doesn't use a differential receiver. Because of # this there is a chance that one of the differential pairs will appear # to have changed to the new state while the other is still in the old # state. The following state machine detects transitions and waits an # extra sampling clock before decoding the state on the differential # pair. This transition period # will only ever last for one clock as # long as there is no noise on the line. If there is enough noise on # the line then the data may be corrupted and the packet will fail the # data integrity checks. # self.submodules.lsr = lsr = FSM() dpair = Signal(2) self.comb += dpair.eq(Cat(usbn, usbp)) # output signals for use by the clock recovery stage line_state_dt = Signal() line_state_dj = Signal() line_state_dk = Signal() line_state_se0 = Signal() line_state_se1 = Signal() # If we are in a transition state, then we can sample the pair and # move to the next corresponding line state. lsr.act("DT", line_state_dt.eq(1), Case(dpair, { 0b10 : NextState("DJ"), 0b01 : NextState("DK"), 0b00 : NextState("SE0"), 0b11 : NextState("SE1") }) ) # If we are in a valid line state and the value of the pair changes, # then we need to move to the transition state. lsr.act("DJ", line_state_dj.eq(1), If(dpair != 0b10, NextState("DT"))) lsr.act("DK", line_state_dk.eq(1), If(dpair != 0b01, NextState("DT"))) lsr.act("SE0", line_state_se0.eq(1), If(dpair != 0b00, NextState("DT"))) lsr.act("SE1", line_state_se1.eq(1), If(dpair != 0b11, NextState("DT"))) ####################################################################### # Clock and Data Recovery # # The DT state from the line state recovery state machine is used to align to # transmit clock. The line state is sampled in the middle of the bit time. # # Example of signal relationships # ------------------------------- # line_state DT DJ DJ DJ DT DK DK DK DK DK DK DT DJ DJ DJ # line_state_valid ________----____________----____________----________----____ # bit_phase 0 0 1 2 3 0 1 2 3 0 1 2 0 1 2 # # We 4x oversample, so make the line_state_phase have # 4 possible values. line_state_phase = Signal(2) self.line_state_valid = Signal() self.line_state_dj = Signal() self.line_state_dk = Signal() self.line_state_se0 = Signal() self.line_state_se1 = Signal() self.sync += [ self.line_state_valid.eq(line_state_phase == 1), If(line_state_dt, # re-align the phase with the incoming transition line_state_phase.eq(0), # make sure we never assert valid on a transition self.line_state_valid.eq(0), ).Else( # keep tracking the clock by incrementing the phase line_state_phase.eq(line_state_phase + 1) ), # flop all the outputs to help with timing self.line_state_dj.eq(line_state_dj), self.line_state_dk.eq(line_state_dk), self.line_state_se0.eq(line_state_se0), self.line_state_se1.eq(line_state_se1), ]