如何根据UART传输协议将数据发送出去呢?

00 简介和接收部分相反,uart发送数据部分是cpu将需要发送的数据写到发送数据寄存器(tx_data),发送模块进行数据的发送。由于系统时钟速率一般会比uart发送数据快,所以发送数据将缓存到发送数据fifo(tx_fifo)。当tx_fifo非空时,发送数据模块会根据uart传输协议将数据发送出去,直到tx_fifo为空。
类似的,发送模块也涉及到arm时钟和26mhz功能时钟。其中 发送fifo读写逻辑是arm时钟域,发送数据状态机和同步逻辑等是功能时钟域 。
01 模块接口与描述
02 实现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; endend// nextstate transformalways@(*) 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 endcaseend第三段状态机,信号赋值:
// output signalalways@(posedge clk26m ornegedge rst26m_) begin if(!rst26m_) begin tx_bpsen <= 1'b0; tx_start <= 1'b0; utxd_o <= 1'b1; data_cnt <= 4'd0; baud_cnt <= 4'd0; end elsebegin case(nextstate) idle: begin tx_start <= 1'b1; baud_cnt <= 4'd0; data_cnt <= 4'd0; end irq: begin tx_bpsen <= 1'b1; tx_start <= 1'b0; end start_bit: begin if(tx_bpsclk) begin utxd_o <= 1'b0; end end tx_data: begin if(tx_bpsclk) begin utxd_o <= data_tx[data_cnt]; data_cnt <= data_cnt + 1'b1; end end check_bit: begin if(tx_bpsclk) begin // odd check if(parity_syn2) begin utxd_o <= ^data_tx; end // even check elsebegin utxd_o <= ^~data_tx; end end end stop: begin if(tx_bpsclk) begin utxd_o <= 1'b1; end end delay: begin if(tx_bpsclk) begin baud_cnt <= baud_cnt + 1'b1; utxd_o <= 1'b1; // the delay between twice send data is 1 end end endcase endend接收数据fifo控制
tx_fifo使用同步fifo设计,工作在apb时钟域。
tx_fifo的读逻辑使用一段式状态机产生。首先判断fifo是否为空,发送状态机的发送请求tx_start是否有效。两个信号都有效时将产生读fifo使能和发送数据响应,通知发送状态机可以开始发送数据。
注意读fifo使能仅有效一个apb时钟周期,待tx_start不使能时disable发送数据响应。等待一个状态后状态机回到初始态(等待一个状态是为了确保发送状态机已经进行跳转,避免tx_ack和fifo读使能一直有效)。
// this state machine to receive data from rx fifoalways@(posedge clk ornegedge rst_) begin if(!rst_) begin tx_ack <= 1'b0; tx_fifo_rinc <= 1'b0; rdata_state <= 2'b0; end elsebegin case(rdata_state) 2'b00: begin if(!tx_fifo_rempty && tx_start_delay2) begin tx_ack <= 1'b1; tx_fifo_rinc <= 1'b1; rdata_state <= 2'b01; end end 2'b01: begin tx_fifo_rinc <= 1'b0; if(!tx_start_delay2) begin tx_ack <= 1'b0; rdata_state <= 2'b10; end end 2'b10: begin rdata_state <= 2'b0; end endcase endendtx_fifo写逻辑放在reg_if模块,apb写tx_data寄存器时,产生写使能信号,将寄存器数据放到tx_fifo中。

领邦仪器研发无线电暗箱快速检测设备
数据挖掘的定义及算法
西门子启动万人裁员 节省22亿欧元成本
全面!中国科学院研究生院生物传感器课件(附下载)
盘点国产显卡厂家
如何根据UART传输协议将数据发送出去呢?
5G干扰整治措施
VR野生动物系统,拉近了人们与野生动物之间的距离
DMB-T 有什么扩展功能来帮助运营商开展更多的应用业务?
企业能源管控平台概述、结构及功能
华为P50系列 将带来两款新配色
李楠:iPhone12 Pro屏幕黑边退步
基于VB 6.O编程语言的永磁无刷电机的设计
简述液压传动的工作原理
数显卡尺的使用方法_数显卡尺的使用注意事项
电表互感器匝数倍率怎么看?
如何提高抗干扰能力和电磁兼容性
手机上那么多孔,IP68级防水是怎么做到的?
联发科董事长将与娄勤俭会面 瞄准TD-LTE实验网
导热硅脂使用注意事项