全球最实用的IT互联网信息网站!

AI人工智能P2P分享&下载搜索网页发布信息网站地图

当前位置:诺佳网 > 电子/半导体 > 接口/总线/驱动 >

如何实现串口数据的接收呢?

时间:2023-06-05 15:24

人气:

作者:admin

标签: 数据  串口  如何  实现   

导读:UART接收数据部分是接收另一个串口设备发送的数据,缓存到接收FIFO中。FIFO快要写满时,产生中断通知CPU拿取数据,实现串口数据的接收。...

00 简介

UART接收数据部分是接收另一个串口设备发送的数据,缓存到接收FIFO中。FIFO快要写满时,产生中断通知CPU拿取数据,实现串口数据的接收。

模块涉及到两个时钟域,ARM时钟和26MHz功能时钟。其中 接收FIFO读写逻辑是ARM时钟域,接收数据状态机和同步逻辑等是功能时钟域

01 模块接口与描述

1.jpg

2.jpg

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

第三段状态机,信号赋值:

// output signal state
always@(posedge clk26m ornegedge rst26m_) begin
    if(!rst26m_) begin
        rx_bpsen <= 1'b0;
        data_rx  <= 8'd0;
        data_cnt <= 4'd0;
        p_error  <= 1'b0;
        st_error <= 1'b0;
        rx_start <= 1'b0;
        start_right <= 1'b0;
    end
    elsebegin
        case(nextstate)
        IDLE: begin
            rx_bpsen    <= 1'b0;
            data_cnt    <= 4'd0;
            st_error    <= 1'b0;
            p_error     <= 1'b0;
            rx_start    <= 1'b0;
            start_right <= 1'b0;
        end
        START: begin
            rx_bpsen    <= 1'b1;
            if(rx_bpsclk) begin
                if(urxd_i == 1'b0) begin
                    start_right <= 1'b1;
                end
                elsebegin
                    start_right <= 1'b0;
                end
            end
        end
        RX_DATA: begin
            if(rx_bpsclk) begin
                data_rx[data_cnt] <= urxd_i;
                data_cnt <= data_cnt + 1'b1;
            end
        end
        CHECK_DATA: begin
            if(rx_bpsclk) begin
                // odd check
                if(parity_syn2) begin
                    if(^data_rx == urxd_i) begin// odd check is wrong
                        p_error  <= 1'b1;
                        rx_bpsen <= 1'b0;
                    end
                end
                // even check
                elsebegin
                    if(^data_rx == !urxd_i) begin// even check is wrong
                        p_error  <= 1'b1;
                        rx_bpsen <= 1'b0;
                    end
                end
            end
        end
        STOP: begin
            if(rx_bpsclk) begin
                if(urxd_i == 1'b0) begin// stop bit is wrong
                    st_error <= 1'b1;
                    rx_bpsen <= 1'b0;
                end
            end
        end
        SEND: begin
            rx_start <= 1'b1;
        end
        endcase
    end
end
  • 接收数据FIFO控制

接收状态机的SEND状态表示1Byte数据接收完成,此状态会产生一个rx_start信号。

FIFO写控制部分通过监控此信号产生写使能rx_fifo_winc(1个ARM时钟周期)和接收响应rx_ack,SEND状态发现rx_ack后释放rx_start,回到IDLE状态。由于FIFO写控制是在ARM时钟域进行,握手的时间很短,不会对接收下一Byte数据产生影响。

// this state machine to send data to RX FIFO
always@(posedge clk ornegedge rst_) begin
    if(!rst_) begin
        rx_ack       <= 1'b0;
        rx_fifo_winc <= 1'b0;
        wdata_state  <= 2'b0;
    end
    elsebegin
        case(wdata_state)
        2'b00: begin
            if(!rx_fifo_wfull && rx_start_delay2) begin
                rx_ack       <= 1'b1;
                rx_fifo_winc <= 1'b1;
                wdata_state  <= 2'b01;
            end
        end
        2'b01: begin
            rx_fifo_winc    <= 1'b0;
            if(!rx_start_delay2) begin
                rx_ack      <= 1'b0;
                wdata_state <= 2'b10;
            end
        end
        2'b10: begin
            wdata_state <= 2'b0;
        end
        endcase
    end
end

FIFO读逻辑放在reg_if模块,APB读RX_DATA寄存器时,产生读使能信号,FIFO将数据放到寄存器中。

温馨提示:以上内容整理于网络,仅供参考,如果对您有帮助,留下您的阅读感言吧!
相关阅读
本类排行
相关标签
本类推荐

CPU | 内存 | 硬盘 | 显卡 | 显示器 | 主板 | 电源 | 键鼠 | 网站地图

Copyright © 2025-2035 诺佳网 版权所有 备案号:赣ICP备2025066733号
本站资料均来源互联网收集整理,作品版权归作者所有,如果侵犯了您的版权,请跟我们联系。

关注微信