电子说
和接收部分相反,UART发送数据部分是CPU将需要发送的数据写到发送数据寄存器(TX_DATA),发送模块进行数据的发送。由于系统时钟速率一般会比UART发送数据快,所以发送数据将缓存到发送数据FIFO(TX_FIFO)。当TX_FIFO非空时,发送数据模块会根据UART传输协议将数据发送出去,直到TX_FIFO为空。
类似的,发送模块也涉及到ARM时钟和26MHz功能时钟。其中 发送FIFO读写逻辑是ARM时钟域,发送数据状态机和同步逻辑等是功能时钟域 。
UART_TX模块主要由三部分组成: 配置信息同步 、TX_FIFO读控制部分和 发送状态机 。
配置信息是reg_if模块由APB总线配置寄存器产生,功能时钟域做两级同步处理。(比如校验位使能、奇偶校验控制、停止位使能等)
发送数据FIFO控制部分将FIFO中的数据读出,通过发送数据状态机将数据发送。
发送状态机是根据串口协议划分,分为IDLE、IRQ、START_BIT、TX_DATA、CHECK_BIT、STOP和DELAY六种状态。
配置信息同步
和接收模块类似,由于配置信息是由APB时钟产生,到接收模块的功能时钟域需要做同步处理。配置信息是电平信号,通常不会像数据一样变化快,所以只需要两级同步。
接收状态机
使用典型的三段式状态机设计,状态转移图如下:
uart发送状态转移图
IDLE: 发送状态机的IDLE状态会产生tx_start的发送请求信号,FIFO读逻辑部分会判断读空信号tx_fifo_rempty和tx_start,如果TX_FIFO非空且发送请求有效,则产生发送响应tx_ack,并发出FIFO读使能。IDLE状态机内发现tx_ack有效,跳转到IRQ状态。IRQ: IRQ状态目的是等待FIFO数据读出。进入IRQ后使能波特率时钟,tx_start信号disable,跳转到START_BIT。
START_BIT: 发送起始位。拉低utxd_o后跳转到发送数据状态TX_DATA。
TX_DATA: 发送从TX_FIFO读出的8bit数据,发送完8bit数据后判断校验位是否使能(check_syn2),使能则进入CHECK_BIT,不使能则进入STOP状态。
CHECK_BIT: 8bit数据按位异或(偶校验)或同或(奇校验),计算出校验位发送,判断是否使能停止位(stop_bit_syn2),如使能停止位则进入STOP状态,不使能则进入DELAY状态。
这里提一下 奇偶校验 。
所谓奇校验,就是判断发送的数据位中1的个数是否是奇数,如果数据位中1的个数是偶数,那就给校验位赋值1;如果数据位中1的个数是奇数,那就给校验位赋值0。目的是确保发送的数据中1的个数是奇数。
偶校验则相反,判断发送的数据位中1的个数是否是偶数,如果数据位中1的个数是偶数,那就给校验位赋值0;如果数据位中1的个数是奇数,那就给校验位赋值1。目的是确保发送的数据中1的个数是偶数。
实现时,奇偶校验可以用同或和异或操作计算,相同的8bit数奇偶校验的值一定是相反的。
STOP: STOP状态拉高utxd_o,然后进入DELAY状态。
DELAY: DELAY状态控制相邻两次发送之间的间隔,间隔时间以波特率时钟为单位,受CPU控制(配置字two_tx_delay),默认delay两个波特率时钟周期。延时后回到IDLE状态进行等待或下一Byte数据传输。
前两段状态机,状态跳转:
// 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(tx_ack_delay2) begin
nextstate = IRQ;
end
elsebegin
nextstate = IDLE;
end
end
IRQ: begin
if(tx_bpsclk) begin
nextstate = START_BIT;
end
elsebegin
nextstate = IRQ;
end
end
START_BIT: begin
if(tx_bpsclk) begin
nextstate = TX_DATA;
end
elsebegin
nextstate = START_BIT;
end
end
TX_DATA: begin
// send 8 bit data
if(data_cnt < 4'd8) begin
nextstate = TX_DATA;
end
elsebegin
if(tx_bpsclk) begin
if(check_syn2) begin
nextstate = CHECK_BIT;
end
elsebegin
nextstate = STOP;
end
end
elsebegin
nextstate = TX_DATA;
end
end
end
CHECK_BIT: begin
if(tx_bpsclk) begin
if(stop_bit_syn2) begin
nextstate = STOP;
end
elsebegin
nextstate = DELAY;
end
end
elsebegin
nextstate = CHECK_BIT;
end
end
STOP: begin
if(tx_bpsclk) begin
nextstate = DELAY;
end
elsebegin
nextstate = STOP;
end
end
DELAY: begin
if(baud_cnt < two_tx_delay_syn2) begin
nextstate = DELAY;
end
elsebegin
nextstate = IDLE;
end
end
default: begin
nextstate = IDLE;
end
endcase
end