00 簡介
UART接收數(shù)據(jù)部分是接收另一個串口設(shè)備發(fā)送的數(shù)據(jù),緩存到接收FIFO中。FIFO快要寫滿時,產(chǎn)生中斷通知CPU拿取數(shù)據(jù),實現(xiàn)串口數(shù)據(jù)的接收。
模塊涉及到兩個時鐘域,ARM時鐘和26MHz功能時鐘。其中 接收FIFO讀寫邏輯是ARM時鐘域,接收數(shù)據(jù)狀態(tài)機和同步邏輯等是功能時鐘域 。
01 模塊接口與描述
02 實現(xiàn)
UART_RX模塊主要由三部分組成: 配置信息同步 、接收狀態(tài)機和 接收數(shù)據(jù)FIFO控制 。
配置信息是reg_if模塊由APB總線配置寄存器產(chǎn)生,功能時鐘域做兩級同步處理。
接收狀態(tài)機是根據(jù)串口協(xié)議劃分,分為IDLE、START、RX_DATA、CHECK_DATA、STOP和SEND六種狀態(tài)。
接收數(shù)據(jù)FIFO控制部分將接收完成的數(shù)據(jù)寫入到FIFO,在CPU讀取RX_FIFO寄存器時將FIFO數(shù)據(jù)讀出送到RX_FIFO寄存器。
- 配置信息同步
由于配置信息是由ARM時鐘產(chǎn)生,到接收模塊的功能時鐘域需要做同步處理。配置信息是電平信號,通常不會像數(shù)據(jù)一樣變化快,所以只需要兩級同步。
- 接收狀態(tài)產(chǎn)生
接收數(shù)據(jù)停止位狀態(tài)指示st_error和接收數(shù)據(jù)校驗位狀態(tài)指示p_error是串口校驗位和停止位檢測狀態(tài)指示。前者為1表示停止位錯誤;后者為1表示校驗位錯誤。兩個狀態(tài)位都會傳到reg_if模塊,指示URAT當前狀態(tài),供CPU查詢。當CPU發(fā)現(xiàn)停止位或者校驗位錯誤時,會決定當前數(shù)據(jù)的處理方式(丟棄或者接受),清除狀態(tài)位(即寫1清0)。reg_if模塊發(fā)現(xiàn)該狀態(tài)位清除后,會回送一個ack到接收模塊,即st_error_ack和p_error_ack。接收模塊接收到ack后釋放狀態(tài)指示st_error和p_error,繼續(xù)接收數(shù)據(jù)。
這個過程就是狀態(tài)位的握手,本模塊設(shè)計方式是握手期間,即發(fā)現(xiàn)校驗位或者停止位錯誤后停止接收數(shù)據(jù),直到CPU清除狀態(tài)后才開始正常接收。讀者可以根據(jù)自己的需要判斷錯誤后是否繼續(xù)接收數(shù)據(jù)。
- 接收狀態(tài)機
使用典型的三段式狀態(tài)機設(shè)計,包含六種狀態(tài),IDLE、START、RX_DATA、CHECK_DATA、STOP和SEND。
uart接收狀態(tài)轉(zhuǎn)移圖
IDLE:狀態(tài)機從IDLE狀態(tài)開始,檢測到uart_i的下降沿,進入START狀態(tài)。
START:START狀態(tài)起始位是否為低(避免毛刺觸發(fā)狀態(tài)機),起始位正常即進入RX_DATA開始接收數(shù)據(jù)。RX_DATA:接收滿8bit后判斷是否使能校驗位,如使能,進入CHECK_DATA狀態(tài)進行奇偶校驗的判斷;如不使能,直接進入停止狀態(tài)STOP。
CHECK_DATA:CHECK_DATA狀態(tài)判斷奇偶校驗是否正確,不正確則發(fā)出p_error信號,在狀態(tài)寄存器指示校驗錯誤,待CPU處理返回p_error_ack后回到IDLE狀態(tài)。如果正確,判斷是否使能停止位檢查;使能停止位檢查則跳轉(zhuǎn)到STOP狀態(tài);不使能則跳轉(zhuǎn)到SEND狀態(tài)。
STOP:同樣的,在STOP狀態(tài)檢測停止位是否是高電平。如果是,表示停止位正確,跳轉(zhuǎn)到SEND狀態(tài);如果不是,則發(fā)出st_error信號,在狀態(tài)寄存器指示停止位錯誤,待CPU處理返回st_error_ack后回到IDLE狀態(tài)。
SEND:SEND狀態(tài)主要是產(chǎn)生rx_start信號表示8bits數(shù)據(jù)接收正確,可以將數(shù)據(jù)寫到接收FIFO。
前兩段狀態(tài)機,狀態(tài)跳轉(zhuǎn):
// state to nextstate with clk in this block.
always@(posedge clk26m ornegedge rst26m_)begin
if(!rst26m_) begin
state <= IDLE;
end
elsebegin
state <= nextstate;
end
end
// nextstate transform
always@(*) begin
case(state)
IDLE: begin
if(neg_urxd_i) begin
nextstate = START;
end
elsebegin
nextstate = IDLE;
end
end
START: begin
if(start_right) begin// start bit is right,then reserve data
nextstate = RX_DATA;
end
elsebegin
nextstate = IDLE;
end
end
RX_DATA: begin
if(data_cnt < 4'd8) begin// reserve 8 datas
nextstate = RX_DATA;
end
elsebegin
if(rx_bpsclk) begin
if(check_syn2) begin
nextstate = CHECK_DATA;
end
elsebegin
nextstate = STOP;
end
end
elsebegin
nextstate = RX_DATA;
end
end
end
CHECK_DATA: begin
if(p_error_ack_delay2) begin
nextstate = IDLE;
end
elsebegin
if(rx_bpsclk) begin
// p_error:1:parity bit error,0:parity bit error
if(p_error) begin
nextstate = CHECK_DATA;
end
elsebegin
// st_check:1:check stop bit,0:don't check stop bit
if(st_check_syn2) begin
nextstate = STOP;
end
elsebegin
nextstate = SEND;
end
end
end
elsebegin
nextstate = CHECK_DATA;
end
end
end
STOP: begin
if(st_error_ack_delay2) begin
nextstate = IDLE;
end
elsebegin
if(rx_bpsclk) begin
// st_error:1:stop bit error,0:stop bit error
if(st_error) begin
nextstate = STOP;
end
elsebegin
nextstate = SEND;
end
end
elsebegin
nextstate = STOP;
end
end
end
SEND: begin
if(rx_ack_delay2) begin
nextstate = IDLE;
end
elsebegin
nextstate = SEND;
end
end
default: begin
nextstate = IDLE;
end
endcase
end