0
\$\begingroup\$

I am a beginner in Verilog, and as a part of a project, I have to send a sequence of signals to a chip in order to program one of its parameters. This Verilog code will be synthesized on an FPGA, and on startup, the FPGA will send this sequence and never send it again. The timing of the signals is very specific for the chip, and it has to match the picture below, in which I sent the signals using the Analog Discovery 2's pattern generator and got it to work that way in simulation. All the signals shown are to be outputs from the FPGA to the chip.

Timing diagram of sequence

In this picture, each 0 or 1 sent from the FPGA starts in the middle of when the clock is high and ends when the middle of the next clock period is high, and I've marked that on the picture (the second message, 0x14 wasn't indicated as well, sorry). Any time in this diagram when a signal goes up or down asynchronous from the clock (e.g. every data output bit transition), it is exactly in the middle of either the high or low portion of the clock. So I suspect I will need a 20MHz clock as well in the Verilog module.

module RDC_config(
input clk_10MHz,
input clk_20MHz,
input clk_100MHz,
output reg FSYNC,
output [1:0] A_x,
output SOE,
output CS,
output reg SDI,
output S_CLK
);

reg [2:0] state = 1; //initialize current state of state machine register
reg [2:0] next_state = 1; //initialize next state of state machine register
reg [5:0] counter_20MHz = 0; //initialize counter register for 20MHz clock edges
reg [5:0] counter_10MHz = 0; //initialize counter register for 10MHz clock edges
reg SDI = 1'b0; //initialize data line to 0
reg FSYNC = 1'b1; //initialize FSYNC to 1

//initialize state machine or go to next state
always@(posedge clk_100MHz) 
begin
    state <= next_state;
end 

//Counter for tracking number of 10MHz clock edges
always@(posedge clk_10MHz)begin
    counter_10MHz <= counter_10MHz+1;
end

//Counter for tracking number of 20MHz clock edges
always@(posedge clk_20MHz)begin
    counter_20MHz <= counter_20MHz+1;
end


//This state machine changes the excitation frequency parameter of the RDC to be 5KHz.
//It sends out 0x91 as the RDC register address and then 0x14 as the register value.
always@(state or counter_10MHz or counter_20MHz) begin
    case(state)
        0:   //State 0: end state
            begin
               SDI <= 1'b0;
               FSYNC <= 1'b1;
               next_state <= 0;
            end 
        1:   //State 1: wait 5 20MHz clock edges, then set FSYNC low
            if(counter_20MHz == 5)begin
               FSYNC <= 1'b0;
               SDI <= 1'b0;
               next_state <= 2; 
            end
        2:  //State 2: wait one 20MHz clock edge, then set SDI high
            if(counter_20MHz == 6)begin
               FSYNC <= 1'b0;
               SDI <= 1'b1;
               next_state <= 3;
            end
        3:  //State 3: wait two 20MHz clock edges, then set SDI low
            if(counter_20MHz == 8)begin
               FSYNC <= 1'b0;
               SDI <= 1'b0;
               next_state <= 4;
            end
        4:  //State 4: wait four 20MHz clock edges, then set SDI high
            if(counter_20MHz == 12)begin
               FSYNC <= 1'b0;
               SDI <= 1'b1;
               next_state <= 5;
            end        
        5:  //State 5: wait two 20MHz clock edges, then set SDI low
            if(counter_20MHz == 14)begin
               FSYNC <= 1'b0;
               SDI <= 1'b0;
               next_state <= 6;
            end
        6:  //State 6: wait six 20MHz clock edges, then set SDI high
            if(counter_20MHz == 20)begin
               FSYNC <= 1'b0;
               SDI <= 1'b1;
               next_state <= 7;
            end
        7:  //State 7: wait eleven 10MHz clock edges, then set FSYNC high
            if(counter_10MHz == 11)begin
               FSYNC <= 1'b1;
               SDI <= 1'b1;
               next_state <= 8;
            end
        8:  //State 8: wait two 20MHz clock edges from state 6, then set SDI low. 0x91 has been sent.
            if(counter_20MHz == 22)begin
               FSYNC <= 1'b1;
               SDI <= 1'b0;
               next_state <= 9;
            end
        9:  //State 9: wait seven 20MHz clock edges, then set FSYNC low
            if(counter_20MHz == 29)begin
               FSYNC <= 1'b0;
               SDI <= 1'b0;
               next_state <= 10;
            end
        10:  //State 10: wait 18 10MHz clock edges, then set SDI high
            if(counter_10MHz == 18)begin
               FSYNC <= 1'b0;
               SDI <= 1'b1;
               next_state <= 11;
            end
        11:  //State 11: wait 1 10MHz clock edge, then set SDI low
            if(counter_10MHz == 19)begin
               FSYNC <= 1'b0;
               SDI <= 1'b0;
               next_state <= 12;
            end
        12:  //State 12: wait 1 10MHz clock edge, then set SDI high
            if(counter_10MHz == 20)begin
               FSYNC <= 1'b0;
               SDI <= 1'b1;
               next_state <= 13;
            end
        13:  //State 13: wait 1 10MHz clock edge, then set SDI low
            if(counter_10MHz == 21)begin
               FSYNC <= 1'b0;
               SDI <= 1'b0;
               next_state <= 14;
            end
        14:  //State 14: wait 45 20MHz clock edges, then set FSYNC high. 0x14 has been sent
            if(counter_20MHz == 45)begin
               FSYNC <= 1'b1;
               SDI <= 1'b0;
               next_state <= 0;
            end       
    endcase
end

assign SOE = 1'b0; //enable serial configuration on RDC
assign A_x = 2'b11; //set to configuration mode
assign CS = 1'b0; //chip select held low
assign SCLK = clk_10MHz; //RDC SCLK set to 10MHz
endmodule

Right now, I have a module written in Vivado that contains all the signals shown in the timing diagram as well as a 20MHz clock that is used for triggering signals in the middle of high or low periods of the 10MHz clock. It is a FSM that uses two counters to count the number of times a positive edge of the 10 or 20MHz clock is hit and determines whether to set the data output high or low based on that with if statements. Once the FSM gets to the last state, it stays there forever. I've tried configuring it how I normally would with the AD2 pattern generator and it works fine, but inexplicably, when I use the FPGA to send the pattern, it doesn't work despite the Vivado simulation waveforms being nearly identical to the AD2's pattern generator. I've also checked the clock counters and the states in the Vivado simulation to make sure they're correct, and they are. The source code I'm using for this is given above.

What is the best way of going about this problem? Is my method of using an FSM and counting the clock edges the best way to do this or is there a much simpler way of doing it that works? I'm also confused why it doesn't work even though the Vivado simulation shows the pattern being pretty much the same as the AD2 pattern generator.

Thanks

\$\endgroup\$
  • \$\begingroup\$ Please write a specific question, you'll get better answers \$\endgroup\$ – laptop2d Feb 18 at 19:39
  • \$\begingroup\$ What is the actual phase relationship between clk_10MHz and clk_20MHz? Where is your testbench? \$\endgroup\$ – Elliot Alderson Feb 18 at 19:46
  • 1
    \$\begingroup\$ You have three clocks entering the module. That is not ideal. A good synchronous design use one clock and derives all signals from that. It avoids a lot of 'issues' which will NOT show up on simulation but WILL appear in hardware. \$\endgroup\$ – Oldfart Feb 18 at 19:47
  • \$\begingroup\$ @Oldfart The top module has a clock divider and generates all the clocks the project is using from that, which I forgot to mention. Thanks for bringing up that issue. \$\endgroup\$ – SD'Anc Feb 18 at 19:59
  • 1
    \$\begingroup\$ "Those two clocks are synchronous.." That is not guaranteed to work, especially on an FPGA where it can take considerable time to route a derived clock to the start of a clock tree and then distribute it. That is one of the 'issues' I mentioned! \$\endgroup\$ – Oldfart Feb 18 at 20:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.