00 简介
UART接收数据部分是接收另一个串口设备发送的数据,缓存到接收FIFO中。FIFO快要写满时,产生中断通知CPU拿取数据,实现串口数据的接收。
模块涉及到两个时钟域,ARM时钟和26MHz功能时钟。其中 接收FIFO读写逻辑是ARM时钟域,接收数据状态机和同步逻辑等是功能时钟域 。
01 模块接口与描述
02 实现
UART_RX模块主要由三部分组成: 配置信息同步 、接收状态机和 接收数据FIFO控制 。
配置信息是reg_if模块由APB总线配置寄存器产生,功能时钟域做两级同步处理。
接收状态机是根据串口协议划分,分为IDLE、START、RX_DATA、CHECK_DATA、STOP和SEND六种状态。
接收数据FIFO控制部分将接收完成的数据写入到FIFO,在CPU读取RX_FIFO寄存器时将FIFO数据读出送到RX_FIFO寄存器。
- 配置信息同步
由于配置信息是由ARM时钟产生,到接收模块的功能时钟域需要做同步处理。配置信息是电平信号,通常不会像数据一样变化快,所以只需要两级同步。
- 接收状态产生
接收数据停止位状态指示st_error和接收数据校验位状态指示p_error是串口校验位和停止位检测状态指示。前者为1表示停止位错误;后者为1表示校验位错误。两个状态位都会传到reg_if模块,指示URAT当前状态,供CPU查询。当CPU发现停止位或者校验位错误时,会决定当前数据的处理方式(丢弃或者接受),清除状态位(即写1清0)。reg_if模块发现该状态位清除后,会回送一个ack到接收模块,即st_error_ack和p_error_ack。接收模块接收到ack后释放状态指示st_error和p_error,继续接收数据。
这个过程就是状态位的握手,本模块设计方式是握手期间,即发现校验位或者停止位错误后停止接收数据,直到CPU清除状态后才开始正常接收。读者可以根据自己的需要判断错误后是否继续接收数据。
- 接收状态机
使用典型的三段式状态机设计,包含六种状态,IDLE、START、RX_DATA、CHECK_DATA、STOP和SEND。
uart接收状态转移图
IDLE:状态机从IDLE状态开始,检测到uart_i的下降沿,进入START状态。
START:START状态起始位是否为低(避免毛刺触发状态机),起始位正常即进入RX_DATA开始接收数据。RX_DATA:接收满8bit后判断是否使能校验位,如使能,进入CHECK_DATA状态进行奇偶校验的判断;如不使能,直接进入停止状态STOP。
CHECK_DATA:CHECK_DATA状态判断奇偶校验是否正确,不正确则发出p_error信号,在状态寄存器指示校验错误,待CPU处理返回p_error_ack后回到IDLE状态。如果正确,判断是否使能停止位检查;使能停止位检查则跳转到STOP状态;不使能则跳转到SEND状态。
STOP:同样的,在STOP状态检测停止位是否是高电平。如果是,表示停止位正确,跳转到SEND状态;如果不是,则发出st_error信号,在状态寄存器指示停止位错误,待CPU处理返回st_error_ack后回到IDLE状态。
SEND:SEND状态主要是产生rx_start信号表示8bits数据接收正确,可以将数据写到接收FIFO。
前两段状态机,状态跳转:
// 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