Calculating RPM from Angular Changes

For a project, I have to determine the RPM of a turning resolver. I can correctly read the angular position of the resolver as as a hex number via an RDC. This number is then converted into a 14-bit decimal number and then sent to a 7-segment display. To give an idea how this works, when the resolver is at 180 degrees, the RDC will return 0x8000, when it is at 359 degrees, the RDC will return 0xFFFF, and at 0 degrees, the RDC will return 0x0000. The separate module then converts the 16-bit values to a 14-bit value.

I am calculating the RPM in its own Verilog module called RPM_calc. The angular position of the resolver is being read at 1000Hz. Inside RPM_calc, I have clock that samples the position 4 times a second every posedge. Every time this posedge hits, it reads the position data being fed in and moves the previous position into a different register. These two registers are subtracted, and the position difference over time (0.25s) is then used to calculate the RPM. The RPM direction is not displayed, and if the direction results in a negative number, it is converted from 2s complement to a regular number. The res input just determines whether I want a 10 or 12-bit resolution from the RDC. My verilog code is shown below.

module RPM_calc(
input clk_i,                //1000Hz sample clock
input res,
input [13:0] position_i,
output [13:0] RPM_o,
output sample_o
);

reg [8:0] clk_4hz_counter = 0;
reg clk_4hz = 0;

reg [13:0] position_reg;
reg [13:0] prev_position_reg = 0;

always@(posedge clk_i) begin  //4Hz clock generator
clk_4hz_counter <= clk_4hz_counter + 1;
if(clk_4hz_counter == 125) begin
clk_4hz_counter <= 0;
clk_4hz = ~clk_4hz;
end
end

always@(posedge clk_4hz) begin
position_reg <= position_i;
prev_position_reg <= position_reg;
end
//2s complement wires
wire [13:0] deltaP;
wire [13:0] abs_deltaP;

assign deltaP = position_reg-prev_position_reg;
assign abs_deltaP = (deltaP[13])?(~deltaP+1):(deltaP);

//if res is 0, divide by 2^12, else divide by 2^10. 240 = 60*(4Hz)
assign RPM_o = res? 240*(abs_deltaP)/1024: 240*(abs_deltaP)/4096;
assign sample_o = clk_i;

endmodule


The problem I ran into is when the RDC rolls over at 360 degrees. For example, if I sample at 350 degrees, and 0.25s later, I sample at 10 degrees when travelling clockwise, my module thinks I traveled 340 degrees in 0.25s, which is incorrect. I need a way of determining what the correct RPM is when two samples happen with a rollover in between. Does anyone have an idea of how to do this?

Thanks

• Can we assume that the travel is never more than 180 degrees in 250 ms? Commented Apr 15, 2019 at 17:56
• @ThePhoton Unfortunately, we can't assume that. Commented Apr 15, 2019 at 22:44
• Then you'll need to sample the position more often then every 250 ms. What's the maximum sampling interval that allows you to assume no more than 180 degrees travel since the previous sample? Commented Apr 15, 2019 at 23:09
• I could sample at 16Hz and safely assume that. Commented Apr 15, 2019 at 23:33

First, it's not good practice to generate a clock with logic in an FPGA. Instead of generating a 4 Hz clock, generate a 4 Hz strobe, and use it to enable logic that's clocked by the 1000 Hz clock:

reg [7:0] ctr_4Hz;
reg strobe_4Hz;
always @(posedge clk_i) begin
if(ctr_4Hz == 250) begin
ctr_4Hz <= 0;
strobe_4Hz <= 1;
end
else begin
ctr_4Hz <= ctr_4Hz + 1;
strobe_4Hz <= 0;
end
end

always@(posedge clk_i) begin
if(strobe_4Hz) begin
position_reg <= position_i;
prev_position_reg <= position_reg;
end
end

// etc


To solve your actual problem, the easiest way is to assume there can't be more than 180 degrees of travel in 250 ms. If you can make this assumption (because of the mechanics of the system, for example), then just keep track of whether the msb of your position register changes. If the old msb was high and the new msb is low, add 360 degrees (or 0x10000 binary angle units) to the new position before calculating deltaP.

If you need to deal with motion in both directions, then you'll need to keep track of which quadrant the old and new positions are in (this depends only on the 2 msb's of the binary angle) and only use special treatment for transitions from IV to I quadrant or I to IV quadrant (add 0x10000 to whichever position was in the I quadrant).