首先,UART模块在系统中的配置主要包括与CPU的通信、APB总线的读写和模块的功能配置,以及中断信号的产生。CPU通过APB总线与UART模块进行通信,通过配置寄存器的方式实现数据收发、控制UART模块功能和读取模块工作状态等操作。
UART模块的关键组成部分包括状态信息同步、APB总线读写、FIFO读写使能和状态寄存器操作及中断产生。状态信息同步部分将来自接收模块和发送模块的状态指示信息,在系统时钟域进行同步,以保证数据传输的稳定性。
APB总线读写是UART模块与CPU通信的重要途径。APB总线读写包括APB读和APB写两个过程。在APB读过程中,UART模块作为APB从设备,当APB总线发起读操作时,将对应地址的寄存器值送到总线,确保主机能收到数据。在APB写过程中,UART模块从总线上接收数据,并将其放到对应的寄存器地址。
FIFO读写使能部分控制了RX_FIFO的读使能和TX_FIFO的写使能。RX_FIFO读控制包括预取动作和读数据寄存器时的控制逻辑。TX_FIFO写控制则是在CPU写uart_tx时,根据时钟周期调整写使能信号。
状态寄存器操作及中断产生部分负责指示UART模块的四个状态:ST_ERROR、P_ERROR、RX_INT和TX_INT。这些状态由高到低在寄存器uart_status[3:0]中表示,分别表示接收数据停止位出错、接收数据校验位出错、接收数据中断位和发送数据中断位。当uart_status中任何一位状态位1时,中断信号将有效,CPU接收到中断后查询状态寄存器uart_status,处理后对uart_status寄存器写1清零,清掉状态位,即清除中断。
总结来说,UART模块是嵌入式系统中重要的串行通信组件。通过对UART模块的配置、工作原理和关键组成部分的了解,我们可以更好地发挥UART模块在系统中的功能,实现高效的数据传输。在实际应用中,根据具体需求对UART模块进行配置,可以满足不同场景下的数据交互需求。
00 模块简介
CPU通过挂载到APB总线上的UART模块,实现其与外部设备的串行通信。系统配置部分将 实现UART模块与CPU的通信,APB总线的读写和模块的功能配置,中断信号的产生 。
AMBA总线中的APB总线由于功耗小,接口简单,适用于低带宽且不需要更高性能总线的中低速外设。UART是此类常见外设,通常使用APB总线与系统连接。
01 模块接口与描述
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 。
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 。
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