Wednesday, 15 April 2015

verilog - Calculating rolling sum of array


I am trying to implement a rolling average of an array of 12 bit samples in SystemVerilog. New samples are generated and shift into an array via a clocked flip flop. The goal is to have a register that represents the sum of all of the current samples, so I can then take the average with a right-shift.


enter image description here



I've attempted to implement this with the following mix of sequential logic to update the array of data, and combinational logic to total all the array elements. Note that the number of measurements to average will eventually be more like 128-1024:


localparam      numMeasurementsToAverage        =   8'd4;

reg [11:0] voltages [numMeasurementsToAverage:0];

// shift in latest voltage measurement on rising clock
always_ff @ (posedge clk)
if(~rst_n) begin
voltages <= '{default:11'd0};
end

else begin
voltages <= {voltages[numMeasurementsToAverage-1:0], v2p_out_voltage};
end

// calculate the current sum of voltages array
always_comb
if(~rst_n) begin
sumOfVoltages <= 0;
end
else begin

for (int i = 0; i < numMeasurementsToAverage; i=i+1) begin
sumOfVoltages += voltages[i];
end
end

This runs, but the sumOfVoltages keeps increasing... the new array total is added to the array total calculated on the previous clock edge. I need the sumOfVoltages to only reflect the total of the elements currently in the array.


Because the voltages[] array is updating on the clock, the sum should also only update on the clock edge, so I can see an argument for moving the summing logic to a clocked flip flop. However, I don't think I can use a for loop for sequential logic.


I like the for loop approach because it makes it way easier to modify the number of elements in the array, compared to hardcoding addition operators between each element in the array. Is there a shorthand for summing all values within an array, using sequential logic instead of a for loop?


Or alternately, is there a clean way to reset sumOfVoltages to zero on each clock edge, without creating a race condition between the sequential and combinational logic? The target is a Xilinx Zynq FPGA, so I need synthesizable code, not just test bench.



Answer




Your approach is extremely wasteful of resources. You don't need to keep adding up the numbers in the middle of the FIFO. Instead, you add the numbers to an accumulator as they go in, and you subtract them back out of the accumulator when they come out of the FIFO.


enter image description here


This requires just two adders, regardless of the amount of data, and a dual-port block RAM can be used for the FIFO, since you no longer need to access all of the data in it on every clock cycle.


No comments:

Post a Comment

arduino - Can I use TI&#39;s cc2541 BLE as micro controller to perform operations/ processing instead of ATmega328P AU to save cost?

I am using arduino pro mini (which contains Atmega328p AU ) along with cc2541(HM-10) to process and transfer data over BLE to smartphone. I...