差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
rs-232 [2017/03/26 19:48] gongyu [接收器] |
rs-232 [2017/03/26 20:00] (当前版本) gongyu [应用案例] |
||
---|---|---|---|
行 231: | 行 231: | ||
Our implementation works like that: | Our implementation works like that: | ||
- | The module assembles data from the RxD line as it comes. | + | * The module assembles data from the RxD line as it comes. |
- | As a byte is being received, it appears on the "data" bus. Once a complete byte has been received, "data_ready" is asserted for one clock. | + | * As a byte is being received, it appears on the "data" bus. Once a complete byte has been received, "data_ready" is asserted for one clock. |
Note that "data" is valid only when "data_ready" is asserted. The rest of the time, don't use it as new data may come that shuffles it. | Note that "data" is valid only when "data_ready" is asserted. The rest of the time, don't use it as new data may come that shuffles it. | ||
- | Oversampling | + | ===== Oversampling ===== |
An asynchronous receiver has to somehow get in-sync with the incoming signal (it normally doesn't have access to the clock used by the transmitter). | An asynchronous receiver has to somehow get in-sync with the incoming signal (it normally doesn't have access to the clock used by the transmitter). | ||
行 245: | 行 246: | ||
Let's assume that we have a "Baud8Tick" signal available, asserted 921600 times a second. | Let's assume that we have a "Baud8Tick" signal available, asserted 921600 times a second. | ||
- | The design | + | ===== The design ===== |
First, the incoming "RxD" signal has no relationship with our clock. | First, the incoming "RxD" signal has no relationship with our clock. | ||
We use two D flip-flops to oversample it, and synchronize it to our clock domain. | We use two D flip-flops to oversample it, and synchronize it to our clock domain. | ||
+ | <code verilog> | ||
reg [1:0] RxD_sync; | reg [1:0] RxD_sync; | ||
always @(posedge clk) if(Baud8Tick) RxD_sync <= {RxD_sync[0], RxD}; | always @(posedge clk) if(Baud8Tick) RxD_sync <= {RxD_sync[0], RxD}; | ||
- | We filter the data, so that short spikes on the RxD line aren't mistaken with start bits. | + | </code> |
+ | We filter the data, so that short spikes on the RxD line aren't mistaken with start bits. | ||
+ | <code verilog> | ||
reg [1:0] RxD_cnt; | reg [1:0] RxD_cnt; | ||
reg RxD_bit; | reg RxD_bit; | ||
行 268: | 行 272: | ||
if(RxD_cnt==2'b11) RxD_bit <= 1; | if(RxD_cnt==2'b11) RxD_bit <= 1; | ||
end | end | ||
- | A state machine allows us to go through each bit received, once a "start" is detected. | + | </code> |
+ | A state machine allows us to go through each bit received, once a "start" is detected. | ||
+ | <code verilog> | ||
reg [3:0] state; | reg [3:0] state; | ||
行 287: | 行 293: | ||
default: state <= 4'b0000; | default: state <= 4'b0000; | ||
endcase | endcase | ||
- | Notice that we used a "next_bit" signal, to go from bit to bit. | + | </code> |
+ | Notice that we used a "next_bit" signal, to go from bit to bit. | ||
+ | <code verilog> | ||
reg [2:0] bit_spacing; | reg [2:0] bit_spacing; | ||
行 303: | 行 311: | ||
reg [7:0] RxD_data; | reg [7:0] RxD_data; | ||
always @(posedge clk) if(Baud8Tick && next_bit && state[3]) RxD_data <= {RxD_bit, RxD_data[7:1]}; | always @(posedge clk) if(Baud8Tick && next_bit && state[3]) RxD_data <= {RxD_bit, RxD_data[7:1]}; | ||
- | The complete code can be found here. | + | </code> |
- | It has a few improvements; follow the comments in the code. | + | |
- | Links | ||
- | More details on Asynchronous Communication | ||
====== 应用案例 ====== | ====== 应用案例 ====== | ||
+ | This design allows controlling a few FPGA pins from your PC (through your PC's serial port). | ||
+ | |||
+ | * It create 8 outputs on the FPGA (port named "GPout"). GPout is updated by any character that the FPGA receives. | ||
+ | * Also 8 inputs on the FPGA (port named "GPin"). GPin is transmitted every time the FPGA receives a character. | ||
+ | |||
+ | The GP outputs can be used to control anything remotely from your PC, might be LEDs or a coffee machine... | ||
+ | <code verilog> | ||
+ | module serialGPIO( | ||
+ | input clk, | ||
+ | input RxD, | ||
+ | output TxD, | ||
+ | |||
+ | output reg [7:0] GPout, // general purpose outputs | ||
+ | input [7:0] GPin // general purpose inputs | ||
+ | ); | ||
+ | |||
+ | wire RxD_data_ready; | ||
+ | wire [7:0] RxD_data; | ||
+ | async_receiver RX(.clk(clk), .RxD(RxD), .RxD_data_ready(RxD_data_ready), .RxD_data(RxD_data)); | ||
+ | always @(posedge clk) if(RxD_data_ready) GPout <= RxD_data; | ||
+ | |||
+ | async_transmitter TX(.clk(clk), .TxD(TxD), .TxD_start(RxD_data_ready), .TxD_data(GPin)); | ||
+ | endmodule | ||
+ | |||
+ | </code> | ||
+ | |||
+ | Remember to grab the async_receiver and async_transmitter modules here, and to update the clock frequency values inside. |