I have a lock-up problem with my UART receiver project. For each character received I go through 4 states RX_IDLE, RX_GETSTART, RX_GETDATA and RX_STOP. The RX_IDLE state waits for the incoming signal to fall from high to low using my FallingEdgeDetector.
FallingEdgeDetector latches (stops running) once it detects a falling edge and I have to bring a reset input high to get it to look for another falling edge.
The attached image shows the “running” output of my FallingEdgeDetector completely flat-lining. I don’t understand how this is happening because the only time ‘running’ is set to 0 is when a falling edge is detected and the fallDetected output should be 1 at the same time. However, ‘fallDetected’ is 0 and so is ‘running’. They should always be the opposite to each other.
How could this be happening? I’ve tried using different output pins on my FGPA development board - including routing the ‘running’ output to one of the onboard LEDs. Same thing. It will receive sometimes tens or hundreds of characters and then it freezes.
I’ve tried to minimise the project as much as possible.
FallingEdgeDetector:
module FallingEdgeDetector( input logic clk,
input logic rxIn,
input logic reset,
output logic fallDetected,
output logic running
);
logic rxLast;
initial begin
running = 1;
rxLast = 0;
fallDetected = 0;
end
always_ff @( posedge clk )
begin
if( reset )
begin
running = 1;
rxLast = 0;
fallDetected = 0;
end
else
if( running )
begin
if( ( rxLast ) && ( ! rxIn ) )
begin
fallDetected = 1;
running = 0;
end
rxLast = rxIn;
end
end
endmodule
Baud Tick Generator:
module UART_BaudRate_generator #(parameter longint BaudRate=19200) // Bits per second
(
input Clk,
output logic TickX8 // 8 ticks per baud cycle
);
localparam longint freqFPGA = 50000000; // 50MHz
longint BaudRateX8Clocks;
longint currClock8Count;
initial
begin
if( BaudRate == 9600 )
begin
// Number of FPGA clock cycles requires for 1 baud period
// BaudRateClocks = freqFPGA / BaudRate;
BaudRateX8Clocks = 372;
end
TickX8 = 0;
currClock8Count = 0;
end
always @(posedge Clk)
begin
if( currClock8Count >= BaudRateX8Clocks )
begin
currClock8Count = 0;
TickX8 = 1;
end
else
begin
TickX8 = 0;
end
currClock8Count ++;
end
endmodule
CharacterReceiver:
module CharacterReceiver( input logic rxIn,
input logic baudTickX8,
input logic clk,
output byte rxData,
output logic ledBit1,
output logic ledBit2,
output logic ledBit3,
output logic ledBit4,
output logic ledBit5,
output logic ledBit6,
output logic ledBit7,
output logic ledBit8,
output logic ledBitStart,
output logic ledBitStop,
output logic ledPurpleIdle,
output logic ledPurpleStart,
output logic ledPurpleData,
output logic ledPurpleStop,
output logic ledPurpleDetected,
output logic ledPurpleDetectReset,
output logic detectorRunning
);
byte unsigned bitsRemaining = 0;
byte unsigned currentChar = 0;
byte unsigned sampleCount;
byte unsigned sampleSize = 14;
byte unsigned halfSampleSize;
byte unsigned matchCount = 0;
localparam byte detectResetCyclesMax = 50;
assign ledPurpleDetectReset = fallDetectorReset;
assign ledPurpleDetected = fallDetected;
initial
begin
halfSampleSize = 8;
currentChar <= 0;
bitsRemaining <= 8;
sampleCount <= 0;
ledBit1 <= 0;
ledBit2 <= 0;
ledBit3 <= 0;
ledBit4 <= 0;
ledBit5 <= 0;
ledBit6 <= 0;
ledBit7 <= 0;
ledBit8 <= 0;
ledBitStart <= 0;
ledBitStop <= 0;
end
logic fallDetectorReset = 1;
logic fallDetected;
FallingEdgeDetector fallingDetector( clk,
rxIn,
fallDetectorReset,
fallDetected,
detectorRunning );
//--------------------------------------------------------------------------------
// Receive States
//--------------------------------------------------------------------------------
typedef enum
{
RX_IDLE,
RX_GETSTART,
RX_GETDATA,
RX_GETSTOP
} RECEIVESTATE;
RECEIVESTATE rxState = RX_IDLE;
//--------------------------------------------------------------------------------
// HandleRxGetStart
//--------------------------------------------------------------------------------
function void HandleRxGetStart;
if( rxIn == 0 )
matchCount ++;
else
if( rxIn == 1 )
begin
sampleCount = 0;
rxState = RX_IDLE;
detectResetCycles = detectResetCyclesMax;
fallDetectorReset = 1;
matchCount = 0;
end
// We only want to count half of the baud samples to put us in the middle..
//if( sampleCount < halfSampleSize )
if( matchCount < halfSampleSize )
return;
// Start counting samples from the middle..
sampleCount = 0;
matchCount = 0;
bitsRemaining = 8;
ledBitStart = 1;
ledBitStop = 0;
rxState = RX_GETDATA;
endfunction
//--------------------------------------------------------------------------------
// HandleRxGetData
//--------------------------------------------------------------------------------
function void HandleRxGetData;
bit bitVal;
// Wait sampleCount X8 ticks since the middle of the start bit.. or
// sampleCount X8 ticks since the last bit..
if( sampleCount < sampleSize )
return;
// Reset count for next time..
sampleCount = 0;
unique case ( bitsRemaining )
8: currentChar = currentChar | ( rxIn ? 8'h01 : 1'b0 );
7: currentChar = currentChar | ( rxIn ? 8'h02 : 1'b0 );
6: currentChar = currentChar | ( rxIn ? 8'h04 : 1'b0 );
5: currentChar = currentChar | ( rxIn ? 8'h08 : 1'b0 );
4: currentChar = currentChar | ( rxIn ? 8'h10 : 1'b0 );
3: currentChar = currentChar | ( rxIn ? 8'h20 : 1'b0 );
2: currentChar = currentChar | ( rxIn ? 8'h40 : 1'b0 );
1: currentChar = currentChar | ( rxIn ? 8'h80 : 1'b0 );
0: ;
endcase
unique case ( bitsRemaining )
8: ledBit1 = rxIn;
7: ledBit2 = rxIn;
6: ledBit3 = rxIn;
5: ledBit4 = rxIn;
4: ledBit5 = rxIn;
3: ledBit6 = rxIn;
2: ledBit7 = rxIn;
1: ledBit8 = rxIn;
0: ;
endcase
bitsRemaining --;
if( bitsRemaining <= 0 )
begin
// Ready for next time..
bitsRemaining = 8;
rxState = RX_GETSTOP;
end
endfunction
//--------------------------------------------------------------------------------
// HandleRxGetStopBit
//--------------------------------------------------------------------------------
function void HandleRxGetStopBit;
if( sampleCount < sampleSize )
return;
if( rxIn == 1 )
begin
ledBitStop = 1;
ledBitStart = 0;
end
// Reset count for next time..
sampleCount = 0;
detectResetCycles = detectResetCyclesMax;
fallDetectorReset = 1;
rxState = RX_IDLE;
endfunction
byte detectResetCycles = 0;
//--------------------------------------------------------------------------------
// State machine for receiving
//--------------------------------------------------------------------------------
always_ff @( posedge clk )
begin
ledPurpleIdle = ( rxState == RX_IDLE );
ledPurpleStart = ( rxState == RX_GETSTART );
ledPurpleData = ( rxState == RX_GETDATA );
ledPurpleStop = ( rxState == RX_GETSTOP );
if( rxState == RX_IDLE )
begin
if( fallDetectorReset )
begin
if( detectResetCycles > 0 )
begin
detectResetCycles --;
// Leave the reset signal up for a number of clock cycles
end
else
begin
// Clear this now - only needs to be high for 1 clock cycle
fallDetectorReset = 0;
end
end
else
if( fallDetected )
begin
ledBitStart = 0;
ledBitStop = 0;
rxState = RX_GETSTART;
// Don't include transition, get next time
end
end
else
begin
// Service state machine for receiving
if( ( rxState != RX_IDLE ) && ( baudTickX8 ) )
begin
if( sampleCount < sampleSize )
sampleCount ++;
else
sampleCount = 0;
// WARNING!! If you don't add ALL cases, the wrong case will execute instead!!
unique case( rxState )
RX_IDLE : ; // MUST have this!!
RX_GETSTART : HandleRxGetStart();
RX_GETDATA : HandleRxGetData();
RX_GETSTOP : HandleRxGetStopBit();
endcase
end
end
end
endmodule
Testbench:
module SystemVerilogTest1( input logic clk,
input logic i115,
output logic baudTickX8,
output logic txActual,
output logic ledBit1,
output logic ledBit2,
output logic ledBit3,
output logic ledBit4,
output logic ledBit5,
output logic ledBit6,
output logic ledBit7,
output logic ledBit8,
output logic ledBitStart,
output logic ledBitStop,
output logic ledPurpleIdle,
output logic ledPurpleStart,
output logic ledPurpleData,
output logic ledPurpleStop,
output logic ledPurpleDetected,
output logic ledPurpleDetectReset,
output logic detectorRunning
);
byte rxByte;
parameter longint baudRate = 9600;
UART_BaudRate_generator #(baudRate) BaudGen1(
.Clk( clk ),
.TickX8( baudTickX8 ),
);
CharacterReceiver charReceiver( i115, baudTickX8, clk,
rxByte,
ledBit1,
ledBit2,
ledBit3,
ledBit4,
ledBit5,
ledBit6,
ledBit7,
ledBit8,
ledBitStart,
ledBitStop,
ledPurpleIdle,
ledPurpleStart,
ledPurpleData,
ledPurpleStop,
ledPurpleDetected,
ledPurpleDetectReset,
detectorRunning
);
endmodule