Baud Generator
Baud Generator
Here we want to use the serial link at maximum speed, i.e. 115200 bauds. Other slower speeds would also be easy to generate. FPGAs usually run at speed well above 115200Hz (RS-232 is pretty slow by today's standards). That means we use a high-speed clock and divide it down to generate a "tick" as close as possible to 115200 times a second.
reg [3:0] BaudDivCnt; always @(posedge clk) BaudDivCnt <= BaudDivCnt + 1; wire BaudTick = (BaudDivCnt==15);
So "BaudTick" is asserted once every 16 clocks, i.e. 115200 times a second when using a 1.8432MHz clock.
while(1) // repeat forever { acc += 115200; if(acc>=2000000) printf("*"); else printf(" "); acc %= 2000000; }
That prints the "*" in the exact ratio, once every "17.361111111..." loops on average. To obtain the same thing efficiently in an FPGA, we rely on the fact that the serial interface can tolerate a few % of error in the baud frequency generator. It really won't matter if we use "17.3" or "17.4".
It is desirable that the 2000000 be a power of two. Obviously 2000000 is not a power of two. So we change the ratio. Instead of the ratio "2000000/115200", let's use "1024/59" = 17.356. That's very close to our ideal ratio, and makes an efficient FPGA implementation.
// 10 bits for the accumulator ([9:0]), and one extra bit for the accumulator carry-out ([10]) reg [10:0] acc; // 11 bits total! always @(posedge clk) acc <= acc[9:0] + 59; // use only 10 bits from the previous result, but save the full 11 bits wire BaudTick = acc[10]; // so that the 11th bit is the carry-out
Using our 2MHz clock, "BaudTick" is asserted 115234 times a second, a 0.03% error from the ideal 115200.
reg [BaudGeneratorAccWidth:0] BaudGeneratorAcc; always @(posedge clk) BaudGeneratorAcc <= BaudGeneratorAcc[BaudGeneratorAccWidth-1:0] + BaudGeneratorInc; wire BaudTick = BaudGeneratorAcc[BaudGeneratorAccWidth];
One last implementation issue: the "BaudGeneratorInc" calculation is wrong, due to the fact that Verilog uses 32 bits intermediate results, and the calculation exceeds that. Change the line as follow for a workaround.
This line has also the added advantage to round the result instead of truncating. That's it. Now that we have a precise enough Baud generator, we can go ahead with the RS-232 transmitter and receiver modules.