00 模塊簡(jiǎn)介
CPU通過掛載到APB總線上的UART模塊,實(shí)現(xiàn)其與外部設(shè)備的串行通信。系統(tǒng)配置部分將 實(shí)現(xiàn)UART模塊與CPU的通信,APB總線的讀寫和模塊的功能配置,中斷信號(hào)的產(chǎn)生 。
AMBA總線中的APB總線由于功耗小,接口簡(jiǎn)單,適用于低帶寬且不需要更高性能總線的中低速外設(shè)。UART是此類常見外設(shè),通常使用APB總線與系統(tǒng)連接。
01 模塊接口與描述
02 實(shí)現(xiàn)
REG_IF模塊主要由 狀態(tài)信息同步 、 APB總線讀寫 、FIFO讀寫使能和狀態(tài)寄存器操作及中斷產(chǎn)生這幾部分構(gòu)成。
APB總線讀寫:通過APB總線實(shí)現(xiàn)與CPU的通信,通過配置寄存器方式實(shí)現(xiàn)數(shù)據(jù)收發(fā),控制UART模塊功能,讀取模塊工作狀態(tài)等。
FIFO讀寫使能:分別是RF_FIFO的讀使能控制和TX_FIFO的寫使能控制。
狀態(tài)寄存器操作及中斷產(chǎn)生:將TX、RX模塊反饋的工作狀態(tài)體現(xiàn)在狀態(tài)寄存器中,供CPU查詢,并產(chǎn)生中斷信號(hào)通知CPU進(jìn)行處理。
- 狀態(tài)信息同步
配置模塊工作在系統(tǒng)時(shí)鐘域,將收到來自接收模塊和發(fā)送模塊的狀態(tài)指示信息,這部分信號(hào)需要在系統(tǒng)時(shí)鐘域進(jìn)行同步。
- APB總線讀寫
前面我們講過APB讀寫時(shí)序。
APB讀:作為APB從設(shè)備,當(dāng)APB總線發(fā)起讀操作時(shí),需要在合適的時(shí)間將對(duì)應(yīng)地址的寄存器值送到總線(如下圖T3),確保主機(jī)能收到數(shù)據(jù)。此時(shí) PENABLE等于0,PSEL等于1,PWRITE等于0 。
apb讀
APB讀實(shí)現(xiàn)如下:
//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寫:類似的,當(dāng)APB總線上發(fā)起寫操作時(shí),從機(jī)需要在合適的時(shí)間接收總線上的數(shù)據(jù)(如下圖T4),放到對(duì)應(yīng)的寄存器地址。此時(shí) PENABLE等于1,PSEL等于1,PWRITE等于1 。
apb寫
APB寫實(shí)現(xiàn)如下:
//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狀態(tài)寄存器(uart_status)時(shí),如果rx中斷有效(即狀態(tài)位的第1bit位有效),且FIFO不為空,RX_FIFO讀使能一個(gè)時(shí)鐘周期。
或在cpu讀接收數(shù)據(jù)寄存器(uart_rx)時(shí),RX_FIFO讀使能一個(gè)時(shí)鐘周期。
注意由于讀出FIFO數(shù)據(jù)需要1個(gè)時(shí)鐘周期,為了使cpu能及時(shí)讀到數(shù)據(jù),在讀狀態(tài)寄存器時(shí)其實(shí)是一個(gè)預(yù)取動(dòng)作。
// 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時(shí),說明需要UART模塊發(fā)送數(shù)據(jù),APB寫數(shù)據(jù)到寄存器需要1個(gè)時(shí)鐘周期,所以需要在1個(gè)時(shí)鐘之后再寫使能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
- 狀態(tài)寄存器操作及中斷產(chǎn)生
狀態(tài)寄存器指示4個(gè)狀態(tài):ST_ERROR,P_ERROR,RX_INT和TX_INT。由高到低在寄存器uart_status[3:0]。分別表示接收數(shù)據(jù)停止位出錯(cuò)、接收數(shù)據(jù)校驗(yàn)位出錯(cuò)、接收數(shù)據(jù)中斷位和發(fā)送數(shù)據(jù)中斷位。
其中接收數(shù)據(jù)中斷位有效表示RX_FIFO中數(shù)據(jù)量增加到觸發(fā)值,數(shù)據(jù)將滿(觸發(fā)值由cpu配置),通知cpu接收數(shù)據(jù);發(fā)送數(shù)據(jù)中斷位有效表示TX_FIFO中數(shù)據(jù)減少到觸發(fā)值,數(shù)據(jù)將空(觸發(fā)值由cpu配置),通知cpu數(shù)據(jù)將要發(fā)送完畢,需補(bǔ)充數(shù)據(jù)。
從接收模塊接收到的ST_ERROR,P_ERROR信號(hào)響應(yīng)也在此部分產(chǎn)生,表示已經(jīng)收到此狀態(tài)。
// 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