Skip to content

Commit

Permalink
initial commit; V1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
dleibrandt committed Aug 25, 2015
0 parents commit 7eb2e32
Show file tree
Hide file tree
Showing 183 changed files with 83,001 additions and 0 deletions.
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
*.obj
moc_*
*.asy
*.gise
*.ngc
gui/debug
gui/release
gui/thirdparty/qwt-6.1.2
firmware/_ngo
firmware/_xmsgs
firmware/iseconfig
firmware/xlnx_auto_0_xdb
firmware/xst
22 changes: 22 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
This hardware and software was developed at the National Institute of
Standards and Technology (NIST) by employees of the Federal Government
in the course of their official duties. Pursuant to Title 17 Section 105
of the United States Code, this hardware and software is not subject to
copyright protection and is in the public domain. NIST assumes no
responsibility whatsoever for its use by other parties, and makes no
guarantees, expressed or implied, about its quality, reliability, or any
other characteristic.

Commercial equipment and software are identified here for informational
purposes only. Such identification does not imply recommendation of
or endorsement by NIST, nor does it imply that the products so identified
are necessarily the best available for the purpose.

This software is based in part on the work of the Qt (http://www.qt.io)
and Qwt (http://qwt.sf.net) projects, both of which are licensed under
the GNU Lesser General Public License (LGPL). It also uses the Opal
Kelly FrontPanel SDK, which is not distributed here because of copyright
restrictions and may be obtained directly from Opal Kelly
(https://www.opalkelly.com).

We would appreciate acknowledgement if this hardware or software is used.
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# NIST Digital Servo

Ion Storage Group
Time and Frequency Division
National Institute of Standards and Technology
Boulder, CO USA

Authors:
David Leibrandt (david.leibrandt@nist.gov)
Jason Heidecker

The NIST digital servo is designed to be a general purpose
feedback controller, implemented digitally using an FPGA.
The advantages of an all-digital approach include fast and
easy (no soldering) reconfiguration of the feedback transfer
function, loop shapes that go beyond PID, the ability to
perform automatic lock acquisition, and the integration of
diagnostics for easy analysis of open and closed loop system
performance. The NIST digital servo has been optimized for
feedback control of lasers in atomic, molecular, and optical
(AMO) physics experiments, but it should be applicable in other
control applications with similar bandwidth, noise, and loop
shape requirements.

This github repository contains the hardware, firmware, and
software design files, as well as precompiled firmware and
software binaries to run the digital servo on Windows 7.

For more information about the firmware and performance of the
digital servo, as well as example use cases, please refer to
D.~R.~Leibrandt and J.~Heidecker, [arxiv:XXXX.XXXXX](http://arxiv.org) (2015).

For instructions on setting up the digital servo using the
precompiled binaries on Windows 7 (which does not require
installing or using any compilers) and on operation of the GUI,
please see `doc\NIST_digital_servo_manual.pdf`.

The hardware design and fabrication files are located in the
`hardware` folder. The firmware source code files are located
in the `firmware` folder. The GUI source code files are
located in the `gui` folder. And matlab functions for reading
in data files generated by the digital servo are located in the
`matlab` folder.
Binary file added deploy/Windows7_FW28may15/QtCore4.dll
Binary file not shown.
Binary file added deploy/Windows7_FW28may15/QtGui4.dll
Binary file not shown.
Binary file added deploy/Windows7_FW28may15/QtSvg4.dll
Binary file not shown.
Binary file not shown.
Binary file added deploy/Windows7_FW28may15/qwt.dll
Binary file not shown.
Binary file added deploy/Windows7_FW28may15/qwt5.dll
Binary file not shown.
Binary file not shown.
Binary file added doc/Figs/DigitalServoInsideWithLabels.pdf
Binary file not shown.
Binary file added doc/Figs/DigitalServoOutsideWithLabels.pdf
Binary file not shown.
Binary file added doc/Figs/SuperlaserlandOverview.pdf
Binary file not shown.
Binary file added doc/NIST_digital_servo_manual.pdf
Binary file not shown.
192 changes: 192 additions & 0 deletions doc/NIST_digital_servo_manual.tex

Large diffs are not rendered by default.

162 changes: 162 additions & 0 deletions firmware/AD5791.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
///////////////////////////////////////////////////////////////////////////////
// AD5791.v
//
// 7/13/11
// David Leibrandt
//
// AD5791 controller.
//
///////////////////////////////////////////////////////////////////////////////

`include "timescale.v"

module AD5791(
input wire clk_in,
input wire rst_in,

input wire signed [19:0] DAC_in,

output reg ldac_out,
output reg clr_out,
output reg rst_out,
output wire spi_scs_out,
output wire spi_sck_out,
output wire spi_sdo_out,
input wire spi_sdi_in
);

reg spi_trigger;
reg [23:0] spi_data;
wire spi_ready;

SPI #(
.TRANSFER_SIZE(24),
.SPI_CLK_DIV(8'h02), // 8'h02 = run the SPI clock at 25 MHz
.SPI_POLARITY(1'b0) // clock data into the DAC on the clock negative edge
)
SPI_inst(
.clk_in(clk_in),
.rst_in(rst_in),
.trigger_in(spi_trigger),
.data_in(spi_data),
.data_out(cmd_data_out),
.ready_out(spi_ready),
.spi_scs_out(spi_scs_out),
.spi_sck_out(spi_sck_out),
.spi_sdo_out(spi_sdo_out),
.spi_sdi_in(spi_sdi_in)
);

///////////////////////////////////////////////////////////////////////////////
// State machine which controls initialization and communicates with the PC

// State machine definitions
localparam RST1A = 4'h0;
localparam RST1B = 4'h1;
localparam RST1C = 4'h2;
localparam RST2A = 4'h3;
localparam RST2B = 4'h4;
localparam RST2C = 4'h5;
localparam DAC1A = 4'h6;
localparam DAC1B = 4'h7;
localparam DAC1C = 4'h8;

// State
// The next line makes synthesis happy
// synthesis attribute INIT of state_f is "R"
reg [3:0] state_f;
reg [11:0] counter_f;

// State machine - combinatorial part
function [3:0] next_state;
input [3:0] state;
input [11:0] counter;
input ready;

begin
case (state)
RST1A:
if (counter == 12'b1)
next_state = RST1B;
else
next_state = RST1A;
RST1B:
next_state = RST1C;
RST1C:
if (counter == 12'b1)
next_state = RST2A;
else
next_state = RST1C;
RST2A:
if (ready)
next_state = RST2B;
else
next_state = RST2A;
RST2B:
next_state = RST2C;
RST2C:
next_state = DAC1A;
DAC1A:
if (ready)
next_state = DAC1B;
else
next_state = DAC1A;
DAC1B:
next_state = DAC1C;
DAC1C:
next_state = DAC1A;
default:
next_state = DAC1A;
endcase
end
endfunction

// State machine - sequential part
always @(posedge clk_in or posedge rst_in) begin
if (rst_in) begin
state_f <= RST1A;
counter_f <= 12'hFFF;
spi_trigger <= 1'b0;
ldac_out <=1'b0;
clr_out <=1'b1;
rst_out <=1'b0;
end
else begin
state_f <= next_state(state_f, counter_f, spi_ready);
case (state_f)
// Reset the DAC
RST1A: begin
counter_f <= counter_f - 12'b1;
end
RST1B: begin
rst_out <=1'b1;
counter_f <= 12'hFFF;
end
RST1C: begin
counter_f <= counter_f - 12'b1;
end
// Set the control register
RST2A: begin
spi_data <= {1'b0, 3'b010, 20'h00002};
end
RST2B: begin
spi_trigger <= 1'b1;
end
RST2C: begin
spi_trigger <= 1'b0;
end
// Set the DAC register
DAC1A: begin
spi_data <= {1'b0, 3'b001, DAC_in};
end
DAC1B: begin
spi_trigger <= 1'b1;
end
DAC1C: begin
spi_trigger <= 1'b0;
end
endcase
end
end

endmodule
151 changes: 151 additions & 0 deletions firmware/AD8251x2.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
///////////////////////////////////////////////////////////////////////////////
// AD8251x2.v
//
// 7/19/11
// David Leibrandt
//
// AD8251 controller.
//
///////////////////////////////////////////////////////////////////////////////

`include "timescale.v"

module AD8251x2(
input wire clk_in,
input wire rst_in,
input wire [1:0] gain0_in,
input wire [1:0] gain1_in,
output reg A0_out,
output reg A1_out,
output reg WR0_out,
output reg WR1_out
);

// Parameters
parameter CLK_DIV = 8'h19; // run the clock at 2 MHz

// FSM clock divider
reg fsm_clk;
reg [7:0] clk_counter;

always @(posedge clk_in or posedge rst_in) begin
if (rst_in) begin
clk_counter <= 8'b0;
fsm_clk <= 1'b0;
end
else if (clk_counter == (CLK_DIV - 8'b1)) begin
clk_counter <= 8'b0;
fsm_clk <= 1'b1;
end
else begin
clk_counter <= clk_counter + 8'b1;
fsm_clk <= 1'b0;
end
end

// State machine definitions
localparam IDLE = 3'h0;
localparam RST = 3'h1;
localparam SET0A = 3'h2;
localparam SET0B = 3'h3;
localparam SET1A = 3'h4;
localparam SET1B = 3'h5;

// State
// The next line makes synthesis happy
// synthesis attribute INIT of state_f is "R"
reg [2:0] state_f;
reg [7:0] counter_f;
reg [2:0] gain0_f;
reg [2:0] gain1_f;

// State machine - combinatorial part
function [2:0] next_state;
input [2:0] state;
input [7:0] counter;
input [1:0] gain0_in;
input [1:0] gain1_in;
input [2:0] gain0;
input [2:0] gain1;

begin
case (state)
IDLE:
if ({1'b0, gain0_in} != gain0)
next_state = SET0A;
else if ({1'b0, gain1_in} != gain1)
next_state = SET1A;
else
next_state = IDLE;
RST:
if (counter == 8'b1)
next_state = IDLE;
else
next_state = RST;
SET0A:
next_state = SET0B;
SET0B:
next_state = IDLE;
SET1A:
next_state = SET1B;
SET1B:
next_state = IDLE;
default:
next_state = IDLE;
endcase
end
endfunction

// State machine - sequential part
always @(posedge fsm_clk or posedge rst_in) begin
if (rst_in) begin
state_f <= RST;
counter_f <= 8'hFF;
gain0_f <= 3'b100;
gain1_f <= 3'b100;
A0_out <= 1'b0;
A1_out <= 1'b0;
WR0_out <= 1'b0;
WR1_out <= 1'b0;
end
else begin
state_f <= next_state(state_f, counter_f, gain0_in, gain1_in, gain0_f, gain1_f);
case (state_f)
IDLE: begin
A0_out <= 1'b0;
A1_out <= 1'b0;
WR0_out <= 1'b0;
WR1_out <= 1'b0;
end
RST: begin
counter_f <= counter_f - 8'b1;
end
SET0A: begin
gain0_f <= gain0_in;
A0_out <= gain0_in[0];
A1_out <= gain0_in[1];
WR0_out <= 1'b1;
end
SET0B: begin
WR0_out <= 1'b0;
end
SET1A: begin
gain1_f <= gain1_in;
A0_out <= gain1_in[0];
A1_out <= gain1_in[1];
WR1_out <= 1'b1;
end
SET1B: begin
WR1_out <= 1'b0;
end
default: begin
A0_out <= 1'b0;
A1_out <= 1'b0;
WR0_out <= 1'b0;
WR1_out <= 1'b0;
end
endcase
end
end

endmodule
Loading

0 comments on commit 7eb2e32

Please sign in to comment.