upsilon/gateware/rtl/spi/ramp.v

149 lines
3.6 KiB
Coq
Raw Normal View History

2023-06-15 12:24:35 -04:00
/* Copyright 2023 (C) Peter McGoron
* This file is a part of Upsilon, a free and open source software project.
* For license terms, refer to the files in `doc/copying` in the Upsilon
* source distribution.
*/
2022-11-17 17:32:32 -05:00
/* Dynamically adjustable DAC ramping.
* Given an increment voltage and a speed setting, increase the voltage
* to that voltage in increments over a period of time.
* This might not be neccessary for now but I wrote it for possible future
* use.
*/
module ramp #(
parameter DAC_DATA_WID = 20,
parameter DAC_WID = 24,
parameter WAIT_WID = 8,
parameter [WAIT_WID-1:0] READ_WAIT = 10
) (
input clk,
input arm,
input read_setting,
output reg finished,
output reg ready,
input [DAC_WID-1:0] mosi,
output [DAC_WID-1:0] miso,
output reg arm_transfer,
input finished_transfer
input signed [DAC_DATA_WID-1:0] move_to,
input signed [DAC_DATA_WID-1:0] stepsiz,
input signed [DAC_DATA_WID-1:0] wait_time,
output reg signed [DAC_DATA_WID-1:0] setting
);
localparam WAIT_ON_ARM = 0;
localparam WAIT_ON_READ_PART_1 = 1;
localparam WAIT_ON_READ_PART_2 = 2;
localparam WAIT_ON_WRITE = 3;
localparam WAIT_ON_TRANSFER = 4;
localparam WAIT_ON_DISARM = 5;
localparam WAIT_ON_READ_DISARM = 6;
reg [3-1:0] state = WAIT_ON_ARM;
reg [WAIT_WID-1:0] timer = 0;
localparam SIGN_POS = 0;
localparam SIGN_NEG = 1;
reg step_sign = 0;
reg last_transfer = 0;
`define DAC_CMD_WID (DAC_WID - DAC_DATA_WID)
localparam [`DAC_CMD_WID-1:0] read_reg = 4'b1001;
localparam [`DAC_CMD_WID-1:0] write_reg = 4'b0001;
task start_transfer();
case (step_sign)
SIGN_POS: if (setting + stepsiz >= move_to) begin
mosi[DAC_DATA_WID-1:0] <= setting;
last_transfer <= 1;
end else begin
mosi[DAC_DATA_WID-1:0] <= setting + stepsiz;
end
SIGN_NEG: if (setting - stepsiz <= move_to) begin
mosi[DAC_DATA_WID-1:0] <= setting;
last_transfer <= 1;
end else begin
mosi[DAC_DATA_WID-1:0] <= setting - stepsiz;
end
endcase
arm_transfer <= 1;
endtask
always @ (posedge clk) begin
case (state)
WAIT_ON_ARM: if (read_setting) begin
mosi <= {read_reg, {(DAC_DATA_WID){1'b0}}};
arm_transfer <= 1;
state <= WAIT_ON_READ;
ready <= 0;
end else if (arm) begin
ready <= 0;
last_transfer <= 0;
if (realstep != 0) begin
state <= WAIT_ON_WRITE;
end
mosi[DAC_WID-1:DAC_DATA_WID] <= write_reg;
/* 0 for positve, 1 for negative */
step_sign <= move_to > setting;
timer <= wait_time;
end else begin
ready <= 1;
end
/* Why put the wait here? If ramping is necessary then any abrupt
* changes in voltages can be disastrous. After each write the
* design always waits, even if ramping is stopped or done, so
* the next ramp always executes when a safe time has elapsed.
*/
WAIT_ON_WRITE: if (timer < wait_time) begin
timer <= timer + 1;
end else if (!arm || last_transfer) begin
state <= WAIT_ON_DISARM;
finished <= 1;
end else if (arm) begin
start_transfer();
state <= WAIT_ON_TRANSFER;
end
WAIT_ON_TRANSFER: if (finished_transfer) begin
setting <= mosi[DAC_DATA_WID-1:0];
timer <= 0;
state <= WAIT_ON_WRITE;
finished <= 1;
end
WAIT_ON_DISARM: if (!arm) begin
state <= WAIT_ON_ARM;
finished <= 0;
end
WAIT_ON_READ_PART_1: if (finished_transfer) begin
state <= WAIT_ON_READ_PART_2;
arm_transfer <= 0;
mosi <= 0;
timer <= 0;
end
WAIT_ON_READ_PART_2: if (timer < read_wait) begin
read_wait <= read_wait + 1;
end else if (!arm_transfer) begin
arm_transfer <= 1;
end else if (finished_transfer) begin
state <= WAIT_ON_READ_DISARM;
finished <= 1;
arm_transfer <= 0;
setting <= miso[DAC_DATA_WID-1:0];
end
WAIT_ON_READ_DISARM: if (!read_setting) begin
state <= WAIT_ON_ARM;
finished <= 0;
end
endcase
end
endmodule