Sending SPI-style serial data to DAC on register change

You have these signals in two separate always blocks.
Synthesis will not work that way. Also your blocks
are using both edges of clk (one edge for each block
that is). So even trying to rewrite this as one block
will require some change to your logic. Do these
signals really need to change on both edges of clk?
What kind of flip-flop did you want Quartus to make
from this code?

HTH,
Gabor

Hello--

Well, I've finally managed to modify my code so that it can be simulated
using Icarus Verilog and also synthesized using Quartus II tools! I did
exactly as you suggested, gabor - the signals do not need to change on
both edges of clk, so I re-wrote the code to contain a block that is
only triggered on the negedge of clk. So thank you so much for your
suggestions!

Using Icarus and Gtkwave, I've validated that there are changes in the
signals.

However, after synthesizing the code and loading it to my hardware,
nothing useful appears to happen when I attempt to load the DAC with a
control word.

I've used Signaltap II Logic Analyzer to examine what is happening - and
it appears that sdin_dac, fsync_dac, reset_lw, and sclk_dac remain
jammed at zero. There appears to be no activity!

I suspect that this may be due to the fact that something is being
optimized away by the synthesis tools. What could be the issue with
this code?

The modified code of the module is listed below:


// Module to update the DAC via SPI
module dac( rst,
clk,
load_word,
msb_data,
lsb_data,
sdin_dac,
fsync_dac,
reset_lw,
sclk_dac);


input rst; // used to ensure state on startup
input clk;
input [7:0] load_word;

input [7:0] msb_data;
input [7:0] lsb_data;

output sdin_dac;
output fsync_dac;
output reset_lw;
output sclk_dac;

reg sdin_dac;
reg fsync_dac;
reg reset_lw;

reg [15:0] data;
reg [4:0] count;

// clock is continuous
assign sclk_dac = clk;

always @(negedge clk) begin

if (rst) begin
sdin_dac <= 1'b0;
fsync_dac <= 1'b0;
reset_lw <= 1'b0;
count <= 5'b0;
end

else begin

if ( (count < 16) && (load_word == 8'b1) )
count <= count + 1'b1;

if (count == 16) count <= 5'b0;
if (load_word == 1'b0) begin
sdin_dac <= 1'b0;
fsync_dac <= 1'b0;
reset_lw <= 1'b0;
count <= 5'b0;
end

if (load_word == 8'b1) begin
// CS is set high
if(count == 5'b0) begin
sdin_dac <= 1'b0;
fsync_dac <= 1'b1;
data <= {msb_data, lsb_data};
end

// shift out the data
if( (count < 16) && (count >= 1))
sdin_dac <= data[15 - count];

// logic should go back to zero again
if(count == 16) begin
sdin_dac <= 1'b0;
fsync_dac <= 1'b0;
reset_lw <= 1'b1;
end

// change reset_lw back again to zero
if (load_word == 1'b0) reset_lw <= 1'b0;
end // end of load_word

end // if else block
end // clk always


endmodule
 
On Sat, 28 Nov 2009 18:33:46 -0600, Nicholas Kinar <n.kinar@usask.ca>
wrote:

Using Icarus and Gtkwave, I've validated that there are changes in the
signals.

However, after synthesizing the code and loading it to my hardware,
nothing useful appears to happen when I attempt to load the DAC with a
control word.

I've used Signaltap II Logic Analyzer to examine what is happening - and
it appears that sdin_dac, fsync_dac, reset_lw, and sclk_dac remain
jammed at zero. There appears to be no activity!

I suspect that this may be due to the fact that something is being
optimized away by the synthesis tools. What could be the issue with
this code?

I think your problem is more basic than that. Your code says:

input clk;
output sclk_dac;

assign sclk_dac = clk;
If you're not seeing any activity on sclk_dac then you don't have
incoming clock as the last line creates just a connection. How are you
applying clock to the FPGA? Have you done any pin assignment in your
design flow? Also how are you applying reset to your design? You may
want to connect it to an external button or similar but then you have
to apply debounce logic to it to make sure you're getting a clean
reset signal.
--
Muzaffer Kal

DSPIA INC.
ASIC/FPGA Design Services

http://www.dspia.com
 
Hello Muzaffer--

Thank you for your reponse.

I think your problem is more basic than that. Your code says:

input clk;
output sclk_dac;

assign sclk_dac = clk;

If you're not seeing any activity on sclk_dac then you don't have
incoming clock as the last line creates just a connection.
I know, it's really weird, since I should see some activity on sclk_dac.
However, I am also using the i2cslave from opencores.org, and I think
that I am able to read and write registers via I2C. Since the i2cslave
code operates as a state machine, I think that registers are read or
written to on the positive edge of clk. Would it be reasonable to
assume that the i2cslave code would not work if the clock were not running?

Perhaps there is something misconfigured with the LogicTap tools?


How are you
applying clock to the FPGA?
Via a 3.3V-level 30MHz oscillator connected to CLK0 input on the FPGA.


Have you done any pin assignment in your
design flow?
Yes, I've assigned all of the pins via the Quartus II pin planner tools.
I've also reserved all unused pins as tri-stated logic.


Also how are you applying reset to your design? You may
want to connect it to an external button or similar but then you have
to apply debounce logic to it to make sure you're getting a clean
reset signal.

Well, I am simply tying reset low via "assign rst = 0" in a higher-level
module. At this time, I do not have an external hardware-based reset.

Using "assign rst = 0" in a higher-level module seems to work with the
opencores.org i2cslave code.

I have a few FPGA pins attached to GPIOs on a 32-bit microcontroller. I
could try toggling a GPIO, and have that serve as the rst pin.

Thank you so much for your suggestions; it is greatly appreciated!

Nicholas
 
Hello--

I know, it's really weird, since I should see some activity on sclk_dac.
However, I am also using the i2cslave from opencores.org, and I think
that I am able to read and write registers via I2C. Since the i2cslave
code operates as a state machine, I think that registers are read or
written to on the positive edge of clk. Would it be reasonable to
assume that the i2cslave code would not work if the clock were not running?

Perhaps there is something misconfigured with the LogicTap tools?
Yes - apparently the LogicTap II tools were set up incorrectly. I have
now changed the acquisition to be edge-triggered, and thankfully it is
now possible to see the signals toggle. Whew - that was a scare, since
if I did not see anything, then clk would not be active. Perhaps the
30MHz clk cannot be viewed when it the tools are set to continually
sample the logic.

The LogicTap II tools show that something really interesting is
occurring with the sdin_dac signal. This particular signal is the MOSI
(Master-Out, Slave-In) serial data pin which is used to communicate with
my DAC.

It appears that the data is not being clocked out correctly to the DAC.
This probably indicates that there is a logic error in my Verilog code.

Oh well - back to the old simulation board again. I will investigate
what is happening, and post my findings back here in this thread.

Once again, many thanks to everyone for the help!
 
It appears that the data is not being clocked out correctly to the DAC.
This probably indicates that there is a logic error in my Verilog code.

Oh well - back to the old simulation board again. I will investigate
what is happening, and post my findings back here in this thread.

Yes - this was exactly what was happening. After a little bit of
experimentation, I found that the most significant (left-most) bit of
the data word was not being shifted out correctly on the sdin_dac pin.

I can now accurately write control words to my DAC, and the hardware
seems to respond in the appropriate manner!

Once again, thank you so much to the people on this newsgroup who helped
me - gabor, Andy, and Muzaffer. Thank you for sticking with me for
nearly a week and helping me to sort this out.

:)

Nicholas


Final version of the module:
----

// Module to update the DAC via SPI
module dac( rst,
clk,
load_word,
msb_data,
lsb_data,
sdin_dac,
fsync_dac,
reset_lw,
sclk_dac);


input rst; // used to ensure state on startup
input clk;
input [7:0] load_word;

input [7:0] msb_data;
input [7:0] lsb_data;

output sdin_dac;
output fsync_dac;
output reset_lw;
output sclk_dac;

reg sdin_dac;
reg fsync_dac;
reg reset_lw;

reg [15:0] data;
reg [4:0] count;

// clock is continuous
assign sclk_dac = clk;

// data is a larger word
assign data = {msb_data, lsb_data};

always @(negedge clk) begin

if (rst == 1'b1) begin
sdin_dac <= 1'b0;
fsync_dac <= 1'b0;
reset_lw <= 1'b0;
count <= 5'b0;
end

else begin

if ( (count < 16) && (load_word == 8'b1) )
count <= count + 1'b1;
if (count == 16) count <= 5'b0;
if (load_word == 1'b0) begin
sdin_dac <= 1'b0;
fsync_dac <= 1'b0;
reset_lw <= 1'b0;
count <= 5'b0;
end

if (load_word == 8'b1) begin
// CS is set high
if(count == 5'b0) begin
sdin_dac <= 1'b0;
fsync_dac <= 1'b1;
end

// shift out the data
if(count < 16) sdin_dac <= data[15 - count];

// logic should go back to zero again
if(count == 16) begin
sdin_dac <= 1'b0;
fsync_dac <= 1'b0;
reset_lw <= 1'b1;
end

// change reset_lw back again to zero
if (load_word == 1'b0) reset_lw <= 1'b0;
end // end of load_word

end // if else block
end // clk always


endmodule
 

Welcome to EDABoard.com

Sponsor

Back
Top