From 14ffd35f5c14771375e0a28c415abe6ba5db92e1 Mon Sep 17 00:00:00 2001 From: Albert Ou Date: Thu, 4 Jan 2018 19:51:24 -0800 Subject: [PATCH] uart: Eliminate systemic baud rate error with low divisor values This refactors the receiver logic to compensate for the case of the baud rate divisor not being multiple of the oversampling period. Previously, the bit time was effectively rounded to (s * floor(div / s)) cycles, where "s" is the oversampling factor - the number of intermediate samples for each data bit. The remainder r = (div % s) was ignored, thereby resulting in gradually accumulated drift that became significant for divisor values on the same order of magnitude as "s". The revised approach inserts the required additional delay by extending the last "r" samples of a given data bit by one cycle each. --- src/main/scala/devices/uart/UART.scala | 89 +++++++++++--------------- 1 file changed, 37 insertions(+), 52 deletions(-) diff --git a/src/main/scala/devices/uart/UART.scala b/src/main/scala/devices/uart/UART.scala index 449f897..d0220e7 100644 --- a/src/main/scala/devices/uart/UART.scala +++ b/src/main/scala/devices/uart/UART.scala @@ -104,46 +104,38 @@ class UARTRx(c: UARTParams)(implicit p: Parameters) extends UARTModule(c)(p) { val debounce_max = (debounce === UInt(3)) val debounce_min = (debounce === UInt(0)) - val prescaler = Reg(init = UInt(0, uartDivisorBits - uartOversample)) + val prescaler = Reg(UInt(width = uartDivisorBits - uartOversample + 1)) val start = Wire(init = Bool(false)) - val busy = Wire(init = Bool(false)) - val pulse = (prescaler === UInt(0)) && busy + val pulse = (prescaler === UInt(0)) - when (busy) { - prescaler := prescaler - UInt(1) - } - when (start || pulse) { - prescaler := io.div >> uartOversample - } + private val dataCountBits = log2Floor(uartDataBits) + 1 + + val data_count = Reg(UInt(width = dataCountBits)) + val data_last = (data_count === UInt(0)) + val sample_count = Reg(UInt(width = uartOversample)) + val sample_mid = (sample_count === UInt((uartOversampleFactor - uartNSamples + 1) >> 1)) + val sample_last = (sample_count === UInt(0)) + val countdown = Cat(data_count, sample_count) - UInt(1) + + // Compensate for the divisor not being a multiple of the oversampling period. + // Let remainder k = (io.div % uartOversampleFactor). + // For the last k samples, extend the sampling delay by 1 cycle. + val remainder = io.div(uartOversample-1, 0) + val extend = (sample_count < remainder) // Pad head: (sample_count > ~remainder) + val restore = start || pulse + val prescaler_in = Mux(restore, io.div >> uartOversample, prescaler) + val prescaler_next = prescaler_in - Mux(restore && extend, UInt(0), UInt(1)) val sample = Reg(Bits(width = uartNSamples)) val voter = Majority(sample.toBools.toSet) - when (pulse) { - sample := Cat(sample, io.in) - } - - private val delay0 = (uartOversampleFactor + uartNSamples) >> 1 - private val delay1 = uartOversampleFactor - - val timer = Reg(UInt(width = uartOversample + 1)) - val counter = Reg(UInt(width = log2Floor(uartDataBits) + 1)) val shifter = Reg(Bits(width = uartDataBits)) - val expire = (timer === UInt(0)) && pulse - - val sched = Wire(init = Bool(false)) - when (pulse) { - timer := timer - UInt(1) - } - when (sched) { - timer := UInt(delay1-1) - } val valid = Reg(init = Bool(false)) valid := Bool(false) io.out.valid := valid io.out.bits := shifter - val (s_idle :: s_start :: s_data :: Nil) = Enum(UInt(), 3) + val (s_idle :: s_data :: Nil) = Enum(UInt(), 2) val state = Reg(init = s_idle) switch (state) { @@ -154,36 +146,29 @@ class UARTRx(c: UARTParams)(implicit p: Parameters) extends UARTModule(c)(p) { when (!io.in) { debounce := debounce + UInt(1) when (debounce_max) { - state := s_start - start := Bool(true) - timer := UInt(delay0-1) - } - } - } - - is (s_start) { - busy := Bool(true) - when (expire) { - sched := Bool(true) - when (voter) { - state := s_idle - } .otherwise { state := s_data - counter := UInt(uartDataBits) + start := Bool(true) + prescaler := prescaler_next + data_count := UInt(uartDataBits+1) + sample_count := UInt(uartOversampleFactor - 1) } } } is (s_data) { - busy := Bool(true) - when (expire) { - counter := counter - UInt(1) - when (counter === UInt(0)) { - state := s_idle - valid := Bool(true) - } .otherwise { - shifter := Cat(voter, shifter >> 1) - sched := Bool(true) + prescaler := prescaler_next + when (pulse) { + sample := Cat(sample, io.in) + data_count := countdown >> uartOversample + sample_count := countdown(uartOversample-1, 0) + + when (sample_mid) { + when (data_last) { + state := s_idle + valid := Bool(true) + } .otherwise { + shifter := Cat(voter, shifter >> 1) + } } } }