UART系统配置步骤详解

电子说

1.3w人已加入

描述

00 模块简介

CPU通过挂载到APB总线上的UART模块,实现其与外部设备的串行通信。系统配置部分将 实现UART模块与CPU的通信,APB总线的读写和模块的功能配置,中断信号的产生

AMBA总线中的APB总线由于功耗小,接口简单,适用于低带宽且不需要更高性能总线的中低速外设。UART是此类常见外设,通常使用APB总线与系统连接。

01 模块接口与描述

FIFO存储

FIFO存储

02 实现

REG_IF模块主要由 状态信息同步APB总线读写FIFO读写使能状态寄存器操作及中断产生这几部分构成。

APB总线读写:通过APB总线实现与CPU的通信,通过配置寄存器方式实现数据收发,控制UART模块功能,读取模块工作状态等。

FIFO读写使能:分别是RF_FIFO的读使能控制和TX_FIFO的写使能控制。

状态寄存器操作及中断产生:将TX、RX模块反馈的工作状态体现在状态寄存器中,供CPU查询,并产生中断信号通知CPU进行处理。

  • 状态信息同步

配置模块工作在系统时钟域,将收到来自接收模块和发送模块的状态指示信息,这部分信号需要在系统时钟域进行同步。

  • APB总线读写

前面我们讲过APB读写时序。

APB读:作为APB从设备,当APB总线发起读操作时,需要在合适的时间将对应地址的寄存器值送到总线(如下图T3),确保主机能收到数据。此时 PENABLE等于0,PSEL等于1,PWRITE等于0

FIFO存储

apb读

APB读实现如下:

//read reg value
always@(posedge clk ornegedge rst_) begin
    if(!rst_) begin
        prdata_o <= 32'h0;
    end
    elsebegin
        // APB read
        if(psel_i && (!penable_i) && (!pwrite_i)) begin
            case(paddr_i)
            4'h0:
                prdata_o <= uart_tx;
            4'h1:
                prdata_o <= uart_rx;
            4'h2:
                prdata_o <= uart_baud;
            4'h3:
                prdata_o <= uart_conf;
            4'h4:
                prdata_o <= uart_rxtrig;
            4'h5:
                prdata_o <= uart_txtrig;
            4'h6:
                prdata_o <= uart_delay;
            4'h7:
                prdata_o <= uart_status;
            4'h8:
                prdata_o <= uart_rxfifo_stat;
            4'h9:
                prdata_o <= uart_txfifo_stat;
            endcase
        end
    end
end

APB写:类似的,当APB总线上发起写操作时,从机需要在合适的时间接收总线上的数据(如下图T4),放到对应的寄存器地址。此时 PENABLE等于1,PSEL等于1,PWRITE等于1

FIFO存储

apb写

APB写实现如下:

//write reg value
always@(posedge clk ornegedge rst_) begin
    if(!rst_) begin
        uart_tx     <= 32'h0;
        uart_baud   <= 32'hf152;
        uart_conf   <= 32'h34;
        uart_rxtrig <= 32'h1;
        uart_txtrig <= 32'h0;
        uart_delay  <= 32'h2;
    end
    elsebegin
        // APB write
        if(psel_i && penable_i && pwrite_i) begin
            case(paddr_i)
            4'h0:
                uart_tx     <= pwdata_i;
            4'h2:
                uart_baud   <= pwdata_i;
            4'h3:
                uart_conf   <= pwdata_i;
            4'h4:
                uart_rxtrig <= pwdata_i;
            4'h5:
                uart_txtrig <= pwdata_i;
            4'h6:
                uart_delay  <= pwdata_i;
            endcase
        end
    end
end
  • FIFO读写使能

RX_FIFO读控制:

在cpu读uart状态寄存器(uart_status)时,如果rx中断有效(即状态位的第1bit位有效),且FIFO不为空,RX_FIFO读使能一个时钟周期。

或在cpu读接收数据寄存器(uart_rx)时,RX_FIFO读使能一个时钟周期。

注意由于读出FIFO数据需要1个时钟周期,为了使cpu能及时读到数据,在读状态寄存器时其实是一个预取动作。

// FIFO enable control
always@(posedge clk ornegedge rst_) begin
    if(!rst_) begin
        rx_fifo_rinc <= 1'b0;
        state        <= 1'b0;
    end
    elsebegin
        case(state)
        1'b0: begin
            // when ARM read uart_status, judge interrupt bit ,if rx_int is
            // active, or ARM read uart_rx ,rx_fifo_rinc enable 1 clk
            if(psel_i && (!penable_i)&&(!pwrite_i)&&(paddr_i==4'h7)) begin
                if(uart_status[1] && !rx_fifo_rempty) begin
                    rx_fifo_rinc <= 1'b1;
                    state        <= 1'b1;
                end
            end
            // when ARM read data,rx_fifo_rinc enable 1 clk
            if(psel_i &&(!penable_i)&&(!pwrite_i)&&(paddr_i==4'h1)) begin
                rx_fifo_rinc <= 1'b1;
                state        <= 1'b1;
            end
        end
        1'b1: begin
            rx_fifo_rinc <= 1'b0;
            state        <= 1'b0;
        end
        endcase
    end
end

TX_FIFO写控制:

在cpu写uart_tx时,说明需要UART模块发送数据,APB写数据到寄存器需要1个时钟周期,所以需要在1个时钟之后再写使能TX_FIFO。

always@(posedge clk ornegedge rst_) begin
    if(!rst_) begin
        tx_fifo_winc <= 1'b0;
        state_en     <= 2'b0;
    end
    elsebegin
        case(state_en)
        2'b0: begin
            // ARM write uart_tx,tx_fifo_winc enable 1 clk after 1 clk
            if(psel_i && penable_i && pwrite_i && (paddr_i==4'h0)) begin
                state_en <= 2'b01;
            end
        end
        2'b01: begin
            state_en     <= 2'b10;
            tx_fifo_winc <= 1'b1;
        end
        2'b10: begin
            tx_fifo_winc <= 1'b0;
            state_en     <= 2'b0;
        end
        endcase
    end
end
  • 状态寄存器操作及中断产生

状态寄存器指示4个状态:ST_ERROR,P_ERROR,RX_INT和TX_INT。由高到低在寄存器uart_status[3:0]。分别表示接收数据停止位出错、接收数据校验位出错、接收数据中断位和发送数据中断位。

其中接收数据中断位有效表示RX_FIFO中数据量增加到触发值,数据将满(触发值由cpu配置),通知cpu接收数据;发送数据中断位有效表示TX_FIFO中数据减少到触发值,数据将空(触发值由cpu配置),通知cpu数据将要发送完毕,需补充数据。

从接收模块接收到的ST_ERROR,P_ERROR信号响应也在此部分产生,表示已经收到此状态。

// uart_status register operate
always@(posedge clk ornegedge rst_) begin
    if(!rst_) begin
        p_error_ack  <= 1'b0;
        st_error_ack <= 1'b0;
        uart_status  <= 32'h0;
        rx_state     <= 1'b0;
        tx_state     <= 1'b0;
    end
    elsebegin
        if(st_error_syn) begin
            uart_status[3]   <= 1'b1;
        end
        elsebegin
            if(neg_uart_status3) begin
                st_error_ack <= 1'b1;
            end
            elsebegin
                if(!st_error_syn2) begin
                    st_error_ack <= 1'b0;
                end
            end
        end
        if(p_error_syn) begin
            uart_status[2]   <= 1'b1;
        end
        elsebegin
            if(neg_uart_status2) begin
                p_error_ack  <= 1'b1;
            end
            elsebegin
                if(!p_error_syn2) begin
                    p_error_ack  <= 1'b0;
                end
            end
        end
        // when rx_fifo_cnt from less than to equal the rxtrig,
        // rx_int is active
        case(rx_state)
        1'b0: begin
            if(rx_fifo_cnt == (uart_rxtrig[3:0] - 1'b1)) begin
                rx_state      <= 1'b1;
            end
            elsebegin
                rx_state      <= 1'b0;
            end
        end
        1'b1: begin
            if(rx_fifo_cnt == uart_rxtrig[3:0]) begin
                uart_status[1] <= 1'b1;
                rx_state       <= 1'b0;
            end
            elsebegin
                rx_state       <= 1'b1;
            end
        end
        endcase
        // when tx_fifo_cnt from greater than to equal the txtrig,
        // tx_int is active
        case(tx_state)
        1'b0: begin
            if(tx_fifo_cnt == (uart_txtrig[3:0] + 1'b1)) begin
                tx_state       <= 1'b1;
            end
            elsebegin
                tx_state       <= 1'b0;
            end
        end
        1'b1: begin
            if(tx_fifo_cnt == uart_txtrig[3:0]) begin
                uart_status[0] <= 1'b1;
                tx_state       <= 1'b0;
            end
            elsebegin
                tx_state       <= 1'b1;
            end
        end
        endcase
        // ARM write 1 clean 0  uart_status
        if(psel_i && penable_i && pwrite_i && (paddr_i==4'h7)) begin
            uart_status <= uart_status & (~pwdata_i);
        end
    end
end

// produce interrupt to CPU
always @(posedge clk ornegedge rst_) begin
    if(!rst_) begin
	      uart_int_o <= 1'b0;
		end
	  elsebegin
	      if(|uart_status[3:0]) begin
            uart_int_o <= 1'b1;
        end
		    elsebegin
            uart_int_o <= 1'b0;
        end
		end
end

当uart_status中任何一位状态位1中断信号将有效,cpu接收到中断后查询状态寄存器uart_status,处理后对uart_status寄存器写1清零,清掉状态位,即清除中断。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分