Gizmotoy
Newbie level 5
I've been using VHDL for awhile now, and am relatively new to Verilog. I feel like I'm probably making an obvious mistake, but I'm not having much luck finding it.
I'm working on creating a serial interface to a motor controller that uses an 8N1 serial protocol. I'm targeting an Altera Cyclone V SoC. I have some code that generates the start, data, and stop bits. The problem is that there is a particular transition that appears to be occurring at an impossible time.
Here's the controller:
And the testbench:
So the particular issue involves this line:
See here:
You can see that the transition of left_right_sel from 0 to 1 occurs at the cursor in the image. It's in a (posedge Clk) block, which seems to mean that it happened when clks_in_bit was 5208 and data_bit was 6. data_bit is transitioning to 7 at around that time, but it doesn't happen until the next clock, and on that clock clks_in_bit is 0. Therefore, both conditions were not satisfied here. The actual time when left_right_sel transitions to 1 shouldn't happen until a bit later once clks_in_bit has ticked up to 5208 again and data_bit has remained at 7.
What have I done wrong here? My presumption would be that to transition clk_in_bit would have to be 5208 and data_bit would have to be 7 on the same clock cycle. The simulator seems to indicate this hadn't happened, and yet the change in left_right_sel happened anyway.
Thanks for the help. Pretty frustrated by this.
- - - Updated - - -
I can't modify the original post, but two additional points of interest:
* Simulator is Modelsim 10.5b Altera Edition
* If building to FPGA image, it seems like the code might work as expected on hardware. Not sure how to determine if the problem is simulator setup or bad code practices.
Any help or suggestions appreciated.
I'm working on creating a serial interface to a motor controller that uses an 8N1 serial protocol. I'm targeting an Altera Cyclone V SoC. I have some code that generates the start, data, and stop bits. The problem is that there is a particular transition that appears to be occurring at an impossible time.
Here's the controller:
Code Verilog - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 // motor_handler.sv // Controls the Sabertooth 2 channel x 12A motor controller // ------------------------------------------------------------------------------------------------- module motor_handler #( parameter CLK_FREQ_HZ = 50000000, parameter BAUD = 9600 ) ( output reg S1, // Serial TTL output input wire Reset, // Active-high reset input wire Clk, // 50MHz clock input wire Enable, // Enable the sensor input wire [6:0] Left_speed, // Speed of the left wheels (signed) input wire [6:0] Right_speed // Speed of the right wheels (signed) ); // Convert Hz to 10 us worth of clock ticks localparam CLKS_PER_BIT = CLK_FREQ_HZ / BAUD; // 5208 @ 50 MHz and 9600 baud // Bit-times to wait between transmissions localparam INTERWORD_BITS = 5; // Bit to select between left and right logic left_right_sel; // ------------------------------------------------------------------------------------------------- // State logic enum logic [2:0] { SM_RESET, SM_SEND_START_BIT, SM_SEND_DATA_BIT, SM_SEND_STOP_BIT, SM_WAIT } state, next_state; // Number of clocks in the current bit logic [$clog2(CLKS_PER_BIT + 1):0] clks_in_bit; // Counter for number of bits during wait period logic [$clog2(INTERWORD_BITS + 1):0] wait_bit; // Counter for number of bits during the data word logic [3:0] data_bit; // ------------------------------------------------------------------------------------------------- // Manage state transitions always_ff @(posedge Clk) begin case (state) SM_RESET: state <= SM_WAIT; SM_WAIT: if (wait_bit >= INTERWORD_BITS) state <= SM_SEND_START_BIT; else state <= SM_WAIT; SM_SEND_START_BIT: if (clks_in_bit >= CLKS_PER_BIT) state <= SM_SEND_DATA_BIT; else state <= SM_SEND_START_BIT; SM_SEND_DATA_BIT: if (clks_in_bit >= CLKS_PER_BIT && data_bit >= 7) state <= SM_SEND_STOP_BIT; else state <= SM_SEND_DATA_BIT; SM_SEND_STOP_BIT: if (clks_in_bit >= CLKS_PER_BIT) state <= SM_WAIT; else state <= SM_SEND_STOP_BIT; default: state <= SM_RESET; endcase end // ------------------------------------------------------------------------------------------------- // Count the clocks to achieve the correct baud always_ff @(posedge Clk) if (state == SM_WAIT) begin data_bit <= 0; if (clks_in_bit >= CLKS_PER_BIT) begin clks_in_bit <= 0; if (wait_bit >= INTERWORD_BITS) wait_bit <= 0; else wait_bit++; end else clks_in_bit++; end else if (state == SM_SEND_START_BIT || state == SM_SEND_STOP_BIT) begin if (clks_in_bit >= CLKS_PER_BIT) clks_in_bit <= 0; else clks_in_bit++; data_bit <= 0; wait_bit <= 0; end else if (state == SM_SEND_DATA_BIT) begin if (clks_in_bit >= CLKS_PER_BIT) begin clks_in_bit <= 0; if (data_bit >= 7) data_bit <= 0; else data_bit++; end else clks_in_bit++; wait_bit <= 0; end else begin data_bit <= 0; clks_in_bit <= 0; wait_bit <= 0; end // Create the serial output logic [7:0] tmp_byte; always_ff @(posedge Clk) if (state == SM_RESET || state == SM_WAIT || state == SM_SEND_STOP_BIT) begin S1 <= 1; end else if (state == SM_SEND_START_BIT) S1 <= 0; else if (state == SM_SEND_DATA_BIT) begin if (left_right_sel == 0) begin tmp_byte = {left_right_sel, Left_speed}; S1 <= tmp_byte[data_bit]; end else begin tmp_byte = {left_right_sel, Right_speed}; S1 <= tmp_byte[data_bit]; end end else // Error case: Shouldn't be possible to get here S1 <= 1; // Determine what to send next always_ff @(posedge Clk) begin if (state == SM_RESET) left_right_sel <= 0; else if (state == SM_SEND_DATA_BIT && clks_in_bit >= 5208 && data_bit >= 7) left_right_sel <= ~left_right_sel; end endmodule
And the testbench:
Code Verilog - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 // Validate the motor_handler // `timescale 1ns/1ns module test_motor_handler(); logic clock; logic reset; logic s1; logic enable; logic [6:0] left_speed; logic [6:0] right_speed; // Generate the clock always #2 clock <= ~clock; // Instantiate module motor_handler dut(s1, reset, clock, enable, left_speed, right_speed); initial begin // Create reset clock <= 0; reset <= 1; enable <= 1; #6 reset <= 0; left_speed <= 75; right_speed <= 75; end endmodule
So the particular issue involves this line:
Code Verilog - [expand] 1 else if (state == SM_SEND_DATA_BIT && clks_in_bit >= 5208 && data_bit >= 7)
See here:
You can see that the transition of left_right_sel from 0 to 1 occurs at the cursor in the image. It's in a (posedge Clk) block, which seems to mean that it happened when clks_in_bit was 5208 and data_bit was 6. data_bit is transitioning to 7 at around that time, but it doesn't happen until the next clock, and on that clock clks_in_bit is 0. Therefore, both conditions were not satisfied here. The actual time when left_right_sel transitions to 1 shouldn't happen until a bit later once clks_in_bit has ticked up to 5208 again and data_bit has remained at 7.
What have I done wrong here? My presumption would be that to transition clk_in_bit would have to be 5208 and data_bit would have to be 7 on the same clock cycle. The simulator seems to indicate this hadn't happened, and yet the change in left_right_sel happened anyway.
Thanks for the help. Pretty frustrated by this.
- - - Updated - - -
I can't modify the original post, but two additional points of interest:
* Simulator is Modelsim 10.5b Altera Edition
* If building to FPGA image, it seems like the code might work as expected on hardware. Not sure how to determine if the problem is simulator setup or bad code practices.
Any help or suggestions appreciated.