0
votes

I have to design an infrared transmitter using a FPGA and Verilog.

One of the conditions is to send a packet every 10Hz , I have a counter that creates a secondary clock at 10Hz from the master clock (100MHz). The packet contains Start-Gap-Select-Gap-Right-Gap-Left-Gap-Forward-Gap-Backwards-Gap. I have a FSM that do this transition at the postive edge of the 10Hz secondary clock. Each of these blocks within the packet has its size, with Gap being just empty space that separates them. The direction blocks have bigger size when selected and smaller otherwise. With the condition that the receiver has a pulse frequency of 36kHz I have another counter that reduces the master clock to 36kHz which i use to generate the pulse sizes for the Start, Select etc. and make the output led 1 while the counter counts up to that size (for cases start, select..) and 0 for Gap state.

However when I look at the LED through my smartphone camera it shows it is on all the time which is what I expect to see as it should send packets 10 times per second.

The problem is that the car is not moving at all, my question is is this the correct logic of doing the things or I am missing something? Thanks

Requested code:

The counter for the 36kHz pulse

always@(posedge CLK) begin
    if(RESET) begin
       Counter <= 0;
        SEC_CLK <= 0; 
    end
    else if(Counter == 2778) begin
        Counter <= 0;
        SEC_CLK <= 1'b1;
    end
    else begin
        Counter <= Counter + 1;
        SEC_CLK <= 1'b0;
    end
end

The 10Hz counter, don't know whether is good to reduce the 36kHz or use the Master Clock, but it is a nice round number so I used the Master CLock

always@(posedge CLK) begin
    if(sec_counter == 100000) begin
        sec_counter <= 0;
        send <= 1;
    end
    else begin
        sec_counter <= sec_counter +1;
        send <= 0;
    end
 end`

The FSM LOGIC:

always@(Curr_State) begin
           case(Curr_State) 
               1'd0: begin //START 
                   Next_State <= 1'd1;
                   Previous_State <= Next_State;
                   max_count <= StartBurstSize;
                   flag <= 0;
               end
               1'd1: begin //GAP
                   if(Previous_State <= 1'd7)
                       Next_State<=1'd0;
                   else 
                      Next_State <= Previous_State +1;
                   max_count <= GapSize;
                   flag <= 1;
                                       IR_LED = 1'b1;

                  if(change)
                      Curr_State <= Next_State;
                  else 
                      Next_State <= Curr_State;
               end
               1'd2: begin //SELECT
                   Next_State <= 1'd1;
                   Previous_State <= Curr_State;
                   max_count <= CarSelectBurstSize;
                   IR_LED = 1'b0;
                   flag <= 0;
                   if(change)
                       Curr_State <= Next_State;
                   else 
                       Next_State <= Curr_State;
               end
               1'd3: begin //RIGHT
                   if(BTNR)
                       max_count <= AsserBurstSize;
                   else
                       max_count <= DeAssertBurstSize;
                   Next_State <= 1'd1;
                   Previous_State <= Curr_State;
                   flag <= 0;
                   if(change)
                      Curr_State <= Next_State;
                   else 
                      Next_State <= Curr_State;
                       IR_LED = 1'b1;
               end
               1'd4: begin //LEFT
                   if(BTNL)
                       max_count <= AsserBurstSize;
                   else
                       max_count <= DeAssertBurstSize;
                   Next_State <= 1'd1;
                   Previous_State <= Curr_State;
                   flag <= 0;
                   if(change)
                      Curr_State <= Next_State;
                   else 
                      Next_State <= Curr_State;
                       IR_LED = 1'b1;
               end
               1'd5: begin //FORWARD
                   if(BTNU)
                       max_count <= AsserBurstSize;
                   else
                       max_count <= DeAssertBurstSize;
                   Next_State <= 1'd1;
                   Previous_State <= Curr_State;
                   flag <= 0;
                    if(change)
                      Curr_State <= Next_State;
                   else 
                      Next_State <= Curr_State;
                       IR_LED = 1'b1;
               end
               1'd6: begin //Backwards
                   if(BTND)
                       max_count <= AsserBurstSize;
                   else 
                       max_count <= DeAssertBurstSize;
                   Next_State <= 1'd1;
                   Previous_State <= Curr_State;
                   flag <= 0;
                    if(change)
                      Curr_State <= Next_State;
                   else 
                      Next_State <= Curr_State;
                       IR_LED = 1'b1;
               end
           
          endcase
end

SENDING THE PULSES TO THE IR LED

always@(posedge SEC_CLK) begin
    if(send) begin
        if(Pcounter == max_count) begin //COUNTING BLOCK SIZE
            Pcounter <= 0;
            IR_LED=1'b0;   
       end
       else begin
            if(flag)
                IR_LED=1'b0; //GAP
            else 
                IR_LED=1'b1;
            Pcounter <= Pcounter+1;
        end
   end
 end
2
Hard to say without seeing your code. Please include your code in the question. A screenshot of the output waveforms (e.g, in ISim) would also be extremely helpful. - user149341

2 Answers

0
votes

There is no reset on sec_counter, so the behavior could be unpredictable (unless you specified an initial value when you declared the reg). Since you didn’t include the declaration portion of the code, it’s difficult to tell.

Your state machine design is a little unusual and I think you are not getting the behavior you expect. Generally state machines are coded in one of two ways. One method places the next_state calculation into a combinatorial block with all the state machine inputs and the current state in the sensitivity list of the block. A second synchronous always block (i.e. the sensitivity list posedge clk) of code assigns the next_state to the current_state at the posedge of the state machine clock. A second method uses a single synchronous always block for both the state machines and outputs. In this case there is no next_state variable, you simply assign the new value directly to the state variable, making sure to assign the state value for each branch of a case or if/else statement. The second version can run faster since all outputs are registered, the first version uses less logic and I personally find it easier to decode. Since your design is very slow, I’d suggest using that first version.

Your state machine doesn’t actually hold state since no clock is in use—so it’s not actually a state machine. Try running it off your clk signal. Also, make sure to handle the clock domain crossing properly to avoid metastability issues.

0
votes

I don't know if you still care about this question, but in your case statements you have something like

  1'd2: begin //SELECT

or even

Previous_State <= 1'd7

However, 1'd means a decimal number 1-bit wide, so it cannot ever be anything different than 0 or 1, the most significant bits just get discarded.

Have you tried to simulate this?