New to Verilog, Help with Serial Com and Control Lines

K

Kyle H.

Guest
Hello All,

I've been reading around on here (and the rest of the Internet) trying
to find an answer to my question. I am trying to send 24 bits serially
with a latch enable and clock. There is a clock (clk20), to clock in
the bits (ProgWord), and the latch enable (LE). I am changing
ProgWords value from outside the module. I need to send 3 different
24-bit words to this IC I'm trying to communicate with. I get stuck in
a loop, and the 24-bit word is output over and over again. I only want
it to be sent once. I've tried a few different things that I thought
should work, but obviously I don't know enough about Verilog.
My code is below, I'm also up for suggestions on my coding style. And
I realize that there are no provisions for trying to control it to stop
on the 25th bit and reset to 0. I took my attempts out in order to
keep the code 'cleaner' Let me know what you think.

module Prog(clk20, DataOut, LE, busy, clk200, start, ProgWord);

output DataOut; // Serial Data out pin
output LE; // Latch Enable pin
output clk20; // 20MHz clock pin
output busy; // busy indicator

input clk200; // 200MHz input clock
input start;
input [24:0] ProgWord; // 24-bit Programming Word

reg clk20;
reg LE;
reg [4:0] bitCount = 0; // Initialize bit counter


// 20MHz Clock Generator
reg [3:0] clkCount = 0; // Initialize clock counter
always @(posedge clk200)
if (clkCount == 10) // Wait 5, 5ns clock cylces
begin
clk20 = ~clk20; // Toggle 20MHz clock pin high/low
clkCount = 0; // Reset clock counter
end
else clkCount = clkCount + 1; // Increment clock


// set busy if working
assign busy = (bitCount!=0);


// Clock in our 24-bit word
always @ (posedge clk20)
if (bitCount <= 25)
bitCount = bitCount + 1; // Increment bitCount
else bitCount = 0; // Keep bitCount 0


// Keep DataOut in sync with 20MHz clock
reg DataOut;
always @ (posedge clk20)
DataOut = ProgWord[bitCount]; // Tie DataOut to the current
// bit of the word


// Pulse LE high for 1 20MHz clock pulse
always @(posedge clk20)
if (bitCount == 25) LE = 1; // bit 24 is clocked in set LE High,
else LE = 0; // then Low.

endmodule
 
Kyle H. wrote:
Hello All,

I've been reading around on here (and the rest of the Internet) trying
to find an answer to my question. I am trying to send 24 bits serially
with a latch enable and clock. There is a clock (clk20), to clock in
the bits (ProgWord), and the latch enable (LE). I am changing
ProgWords value from outside the module. I need to send 3 different
24-bit words to this IC I'm trying to communicate with. I get stuck in
a loop, and the 24-bit word is output over and over again. I only want
it to be sent once. I've tried a few different things that I thought
should work, but obviously I don't know enough about Verilog.
My code is below, I'm also up for suggestions on my coding style. And
I realize that there are no provisions for trying to control it to stop
on the 25th bit and reset to 0. I took my attempts out in order to
keep the code 'cleaner' Let me know what you think.

module Prog(clk20, DataOut, LE, busy, clk200, start, ProgWord);

output DataOut; // Serial Data out pin
output LE; // Latch Enable pin
output clk20; // 20MHz clock pin
output busy; // busy indicator

input clk200; // 200MHz input clock
input start;
input [24:0] ProgWord; // 24-bit Programming Word
[24:0] is 25 bits.

reg clk20;
reg LE;
reg [4:0] bitCount = 0; // Initialize bit counter


// 20MHz Clock Generator
reg [3:0] clkCount = 0; // Initialize clock counter
always @(posedge clk200)
if (clkCount == 10) // Wait 5, 5ns clock cylces
begin
clk20 = ~clk20; // Toggle 20MHz clock pin high/low
clkCount = 0; // Reset clock counter
end
else clkCount = clkCount + 1; // Increment clock
Clock generator notes:
1) You're dividing by 22, not 10. The output will be 9.09 MHz if the
input is 200 MHz (clk20 is alternately high for 11 cycles, then low
for 11 cycles). clkCount counts through 11 states, 0 through 10.
2) Most people would write synchronous processes only
with non-blocking assignments. A synthesizer may or not complain
about your style here as I don't see any sequential dependencies.

// set busy if working
assign busy = (bitCount!=0);


// Clock in our 24-bit word
always @ (posedge clk20)
if (bitCount <= 25)
bitCount = bitCount + 1; // Increment bitCount
else bitCount = 0; // Keep bitCount 0
If you want your bit counter to stop after sending the input once,
you need to depend on your start input. One approach would
be to increment the count only when either "busy" or "start"
is active. Then in the absence of "start" the count will remain zero.

// Keep DataOut in sync with 20MHz clock
reg DataOut;
always @ (posedge clk20)
DataOut = ProgWord[bitCount]; // Tie DataOut to the current
// bit of the word
The typical way to send serial data is with a shift register rather
than
a 25:1 multiplexer. In your case, the input needs to remain valid
until
you have completed sending the data. With a shift register you would
load the shift register at the assertion of "start" and then shift the
bits out until no longer "busy". Data at the input could change while
start is not asserted.

Again most people would use non-blocking assignments in these
synchonous processes.


// Pulse LE high for 1 20MHz clock pulse
always @(posedge clk20)
if (bitCount == 25) LE = 1; // bit 24 is clocked in set LE High,
else LE = 0; // then Low.

endmodule
 
Thanks for your help gabor. I was using 25 bits to pulse my LE high.
I don't know what I was thinking with the clock. I have since modified
the code a lot and got some results, but only partial sucess, if that's
possible. At first I was using a shift register, I think. Here's some
code that I have stepped away from, but possibly will go back to, if
this is what you are reffering too.

// 20MHz Clk Generator
reg [2:0] clk_count = 0;
always @(posedge clk200)
if (clk_count == 4)
begin
clk20 = ~clk20;
clk_count = 0;
end
else clk_count = clk_count + 1;

// Transmitter state machine
reg [5:0] state;

always @(posedge clk200)
if (state==6'b000011 || state==6'b000001) LE = 1; // Keep LE high
while not sending data.
else LE = 0; // Keep LE low while
sending data

assign busy = (state!=0); // busy

always @(posedge clk200)
case(state)
6'b011000: if(start) state <= 6'b100000; // If start begin Loop
6'b100000: if(clk20) state <= 6'b100001; // bit 0
6'b100001: if(clk20) state <= 6'b100010; // bit 1
6'b100010: if(clk20) state <= 6'b100011; // bit 2
6'b100011: if(clk20) state <= 6'b100100; // bit 3
6'b100100: if(clk20) state <= 6'b100101; // bit 4
6'b100101: if(clk20) state <= 6'b100110; // bit 5
6'b100110: if(clk20) state <= 6'b100111; // bit 6
6'b100111: if(clk20) state <= 6'b101000; // bit 7
6'b101000: if(clk20) state <= 6'b101001; // bit 8
6'b101001: if(clk20) state <= 6'b101010; // bit 9
6'b101010: if(clk20) state <= 6'b101011; // bit 10
6'b101011: if(clk20) state <= 6'b101100; // bit 11
6'b101100: if(clk20) state <= 6'b101101; // bit 12
6'b101101: if(clk20) state <= 6'b101110; // bit 13
6'b101110: if(clk20) state <= 6'b101111; // bit 14
6'b101111: if(clk20) state <= 6'b110000; // bit 15
6'b110000: if(clk20) state <= 6'b110001; // bit 16
6'b110001: if(clk20) state <= 6'b110010; // bit 17
6'b110010: if(clk20) state <= 6'b110011; // bit 18
6'b110011: if(clk20) state <= 6'b110100; // bit 19
6'b110100: if(clk20) state <= 6'b110101; // bit 20
6'b110101: if(clk20) state <= 6'b110110; // bit 21
6'b110110: if(clk20) state <= 6'b110111; // bit 22
6'b110111: if(clk20) state <= 6'b011001; // bit 23
6'b011001: if(clk20) state <= 6'b011000; // LE High
default: if(clk20) state <= 6'b011000; // Loop
endcase

// Output Buffer
reg DataBuff;
always @(state [4:0] or ProgrammingWord)
case(state[4:0])
0: DataBuff <= ProgrammingWord[0];
1: DataBuff <= ProgrammingWord[1];
2: DataBuff <= ProgrammingWord[2];
3: DataBuff <= ProgrammingWord[3];
4: DataBuff <= ProgrammingWord[4];
5: DataBuff <= ProgrammingWord[5];
6: DataBuff <= ProgrammingWord[6];
7: DataBuff <= ProgrammingWord[7];
8: DataBuff <= ProgrammingWord[8];
9: DataBuff <= ProgrammingWord[9];
10: DataBuff <= ProgrammingWord[10];
11: DataBuff <= ProgrammingWord[11];
12: DataBuff <= ProgrammingWord[12];
13: DataBuff <= ProgrammingWord[13];
14: DataBuff <= ProgrammingWord[14];
15: DataBuff <= ProgrammingWord[15];
16: DataBuff <= ProgrammingWord[16];
17: DataBuff <= ProgrammingWord[17];
18: DataBuff <= ProgrammingWord[18];
19: DataBuff <= ProgrammingWord[19];
20: DataBuff <= ProgrammingWord[20];
21: DataBuff <= ProgrammingWord[21];
22: DataBuff <= ProgrammingWord[22];
23: DataBuff <= ProgrammingWord[23];
24:;
25:;
default:;
endcase

// Send the data out
reg DataOut;
always @(posedge clk200) DataOut <= (state<3) | (state[5] & DataBuff);

As for only sending the data once, I have tried many configurations of
allowing the counter to only count while busy or a start signal are
present, but I either end up stuck in a loop or looping my data out,
like I was previously only this time with more code. Again thanks for
your help. Have a nice weekend all.
 
I typed too soon. I just went over a shift register Template inside
Xilinx ISE and recognized it to match up with a way someone else had
explained to send serial data on this group (through a previous
search).

I was using 25bits...Rather I was using the 25th bit to pulse LE high,
at the moment I am actually using 26 bits :O) Looks like I have to
rethink this design over the weekend.
 
Kyle H. wrote:
Thanks for your help gabor. I was using 25 bits to pulse my LE high.
I don't know what I was thinking with the clock. I have since modified
the code a lot and got some results, but only partial sucess, if that's
possible. At first I was using a shift register, I think. Here's some
code that I have stepped away from, but possibly will go back to, if
this is what you are reffering too.

// 20MHz Clk Generator
reg [2:0] clk_count = 0;
always @(posedge clk200)
if (clk_count == 4)
begin
clk20 = ~clk20;
clk_count = 0;
end
else clk_count = clk_count + 1;

// Transmitter state machine
reg [5:0] state;

always @(posedge clk200)
if (state==6'b000011 || state==6'b000001) LE = 1; // Keep LE high
while not sending data.
else LE = 0; // Keep LE low while
sending data

assign busy = (state!=0); // busy
Two notes on the following process:

1) This should really have a reset term. As it stands, you cannot
simulate this. What state should the machine start up in?

2) Looking at the code above you'll realize that clk20 is on
for 5 periods of clk200 then off for 5 periods. So the entire
shifting portion below, i.e. the lines with "if(clk20)" will run
in bursts of 5 states at 200 MHz followed by a gap of 5
clock cycles (of 200 MHz). What you probably meant was to
advance to the next state on an edge of clk20. Why couldn't
the entire process run on clk20? Is "start" a single cycle pulse
on clk200? Do you need to account for hold time on the
output data after the rising edge of clk20? If this is the case
you may want to update the state on (clk20 && (count == 0))
which would advance state one cycle of clk200 after the rising
edge of clk20.

always @(posedge clk200)
case(state)
6'b011000: if(start) state <= 6'b100000; // If start begin Loop
6'b100000: if(clk20) state <= 6'b100001; // bit 0
6'b100001: if(clk20) state <= 6'b100010; // bit 1
6'b100010: if(clk20) state <= 6'b100011; // bit 2
6'b100011: if(clk20) state <= 6'b100100; // bit 3
6'b100100: if(clk20) state <= 6'b100101; // bit 4
6'b100101: if(clk20) state <= 6'b100110; // bit 5
6'b100110: if(clk20) state <= 6'b100111; // bit 6
6'b100111: if(clk20) state <= 6'b101000; // bit 7
6'b101000: if(clk20) state <= 6'b101001; // bit 8
6'b101001: if(clk20) state <= 6'b101010; // bit 9
6'b101010: if(clk20) state <= 6'b101011; // bit 10
6'b101011: if(clk20) state <= 6'b101100; // bit 11
6'b101100: if(clk20) state <= 6'b101101; // bit 12
6'b101101: if(clk20) state <= 6'b101110; // bit 13
6'b101110: if(clk20) state <= 6'b101111; // bit 14
6'b101111: if(clk20) state <= 6'b110000; // bit 15
6'b110000: if(clk20) state <= 6'b110001; // bit 16
6'b110001: if(clk20) state <= 6'b110010; // bit 17
6'b110010: if(clk20) state <= 6'b110011; // bit 18
6'b110011: if(clk20) state <= 6'b110100; // bit 19
6'b110100: if(clk20) state <= 6'b110101; // bit 20
6'b110101: if(clk20) state <= 6'b110110; // bit 21
6'b110110: if(clk20) state <= 6'b110111; // bit 22
6'b110111: if(clk20) state <= 6'b011001; // bit 23
6'b011001: if(clk20) state <= 6'b011000; // LE High
default: if(clk20) state <= 6'b011000; // Loop
endcase
The code below is equivalent to the multiplexer of the
design you first posted. A shift register would look more like:
reg [24:0] shiftreg;
always @ (posedge clk20)
begin
if (some state) shiftreg <= ProgrammingWord; // to load input word
else if (other range of states) shiftreg <= {1'b0,shiftreg[24:1]};
// to shift right
end
assign DataBuff = shiftreg[0];

// Output Buffer
reg DataBuff;
always @(state [4:0] or ProgrammingWord)
case(state[4:0])
0: DataBuff <= ProgrammingWord[0];
1: DataBuff <= ProgrammingWord[1];
2: DataBuff <= ProgrammingWord[2];
3: DataBuff <= ProgrammingWord[3];
4: DataBuff <= ProgrammingWord[4];
5: DataBuff <= ProgrammingWord[5];
6: DataBuff <= ProgrammingWord[6];
7: DataBuff <= ProgrammingWord[7];
8: DataBuff <= ProgrammingWord[8];
9: DataBuff <= ProgrammingWord[9];
10: DataBuff <= ProgrammingWord[10];
11: DataBuff <= ProgrammingWord[11];
12: DataBuff <= ProgrammingWord[12];
13: DataBuff <= ProgrammingWord[13];
14: DataBuff <= ProgrammingWord[14];
15: DataBuff <= ProgrammingWord[15];
16: DataBuff <= ProgrammingWord[16];
17: DataBuff <= ProgrammingWord[17];
18: DataBuff <= ProgrammingWord[18];
19: DataBuff <= ProgrammingWord[19];
20: DataBuff <= ProgrammingWord[20];
21: DataBuff <= ProgrammingWord[21];
22: DataBuff <= ProgrammingWord[22];
23: DataBuff <= ProgrammingWord[23];
24:;
25:;
default:;
endcase

// Send the data out
reg DataOut;
always @(posedge clk200) DataOut <= (state<3) | (state[5] & DataBuff);

As for only sending the data once, I have tried many configurations of
allowing the counter to only count while busy or a start signal are
present, but I either end up stuck in a loop or looping my data out,
like I was previously only this time with more code. Again thanks for
your help. Have a nice weekend all.
Good Luck,
Gabor
 
Kyle H. wrote:
1) I've been seeing the reset term used so much. I think the reason I
havn't been using it, has to do with the way we are using the FPGA. I
am almost trying to use it like a processor in its raw form.
Interfacing with a computer via rs232, and having it execute speed
related commands. It might be a little easier to accomplish what I
want with some type of processor along side the FPGA, to actually issue
the reset command among all the other commands, rather than trying to
make the FPGA do it all by its self. Is this how it's normally done
(w/ a processor along side)?
There are really two different types of reset in an FPGA, and
to my knowledge no "normal" source for asserting reset after
configuration.

The first type of reset occurs during the configuration process.
At this time every flip-flop in the device is initialized from the
configuration bitstream. This does not require an asynchronous
reset signal to the flip-flop. In fact the flip-flop could be
configured
to come up in one state, but later to be asynchronously set to
another.

The other type of reset occurs in response to some signal of
the design after it is running. This is usually driven briefly after
configuration, if only to make the simulation and operation match.
It can be re-asserted by any logic source including a processor
if you choose.

In the case of state machines, it is very important to deal with
at least the first form of reset. The tools cannot guess what
state the machine should come up in after configuration. If
you provide no information, most synthesizers assign the value
zero to any flip-flop including your state bits. However if you
provide an asynchronous reset term to the process, the
synthesis tools will generate a bitstream that initializes the
state to the specified reset state.

There are even more complications with state machines as
implemented by the synthesis tools. Many tools including
XST insist on creating a "one-hot" implemention of state
logic unless you specifically tell it to do otherwise. So now
if you have a state machine designed with binary encoding
and no action defined for state zero, it's not so obvious how
the state logic should come up after configuration. You could
even have a case where no state comes up active (although
I think this shouldn't occur when you have a "default" action).
Then the state machine does nothing.

So you would normally end up with a module that has
a reset input. At a higher level in the design you can
instantiate that module and apply a reset signal to the reset
input, say a signal that stays high for 4 clock cycles after
configuration is complete (Xilinx has a template for this). You
could also connect the reset input to 1'b0 meaning never
reset the module. However in this case the state would still
be initialized correctly by the bitstream during configuration,
because the synthesizer had the reset portion of the process
to show it the correct value of state to start up with.

2) Thanks for that clarification, I wasn't sure how that would actually
work out. I think I will mess around with a shift register today.
Since that seems to be more practical, and much cleaner looking code.

Thanks for your help, this is exactly what I was looking for!
 
1) I've been seeing the reset term used so much. I think the reason I
havn't been using it, has to do with the way we are using the FPGA. I
am almost trying to use it like a processor in its raw form.
Interfacing with a computer via rs232, and having it execute speed
related commands. It might be a little easier to accomplish what I
want with some type of processor along side the FPGA, to actually issue
the reset command among all the other commands, rather than trying to
make the FPGA do it all by its self. Is this how it's normally done
(w/ a processor along side)?

2) Thanks for that clarification, I wasn't sure how that would actually
work out. I think I will mess around with a shift register today.
Since that seems to be more practical, and much cleaner looking code.

Thanks for your help, this is exactly what I was looking for!
 

Welcome to EDABoard.com

Sponsor

Back
Top