1 |
6 |
root |
//---------------------------------------------------------------------------
|
2 |
|
|
// PWM reader
|
3 |
|
|
// ...for variable frequency PWM signals from real world sensors.
|
4 |
|
|
//
|
5 |
|
|
//
|
6 |
|
|
// Description: See description below (which suffices for IP core
|
7 |
|
|
// specification document.)
|
8 |
|
|
//
|
9 |
|
|
// Copyright (C) 2002 John Clayton and OPENCORES.ORG (this Verilog version)
|
10 |
|
|
//
|
11 |
|
|
// This source file may be used and distributed without restriction provided
|
12 |
|
|
// that this copyright statement is not removed from the file and that any
|
13 |
|
|
// derivative work contains the original copyright notice and the associated
|
14 |
|
|
// disclaimer.
|
15 |
|
|
//
|
16 |
|
|
// This source file is free software; you can redistribute it and/or modify
|
17 |
|
|
// it under the terms of the GNU Lesser General Public License as published
|
18 |
|
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
19 |
|
|
// (at your option) any later version.
|
20 |
|
|
//
|
21 |
|
|
// This source is distributed in the hope that it will be useful, but WITHOUT
|
22 |
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
23 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
24 |
|
|
// License for more details.
|
25 |
|
|
//
|
26 |
|
|
// You should have received a copy of the GNU Lesser General Public License
|
27 |
|
|
// along with this source.
|
28 |
|
|
// If not, download it from http://www.opencores.org/lgpl.shtml
|
29 |
|
|
//
|
30 |
|
|
//---------------------------------------------------------------------------
|
31 |
|
|
//
|
32 |
|
|
// Author: John Clayton
|
33 |
|
|
// Date : Jan 28, 2003
|
34 |
|
|
//
|
35 |
|
|
// (NOTE: Date formatted as day/month/year.)
|
36 |
|
|
// Update: 11/03/03 Saved "pwd_counter.v" under the new name "pwm_reader.v" so
|
37 |
|
|
// that the divide_uu module can be integrated into this new
|
38 |
|
|
// module.
|
39 |
|
|
// Update: 13/03/03 Finished coding module, began testing.
|
40 |
|
|
//
|
41 |
|
|
// Update: 03/06/03 Added ack_r signal, so that stb_o would not oscillate when
|
42 |
|
|
// connected directly to the ack_i input.
|
43 |
|
|
//
|
44 |
|
|
// Description
|
45 |
|
|
//---------------------------------------------------------------------------
|
46 |
|
|
// This module reads the pulse width of a repetitive variable duty cycle
|
47 |
|
|
// digital input. Pulse Width Modulated (PWM) inputs are produced by many
|
48 |
|
|
// devices, including certain real world sensors.
|
49 |
|
|
// In this case, the specific sensor for which this module was created
|
50 |
|
|
// is the Analog Devices ADXL202e (a +/- 2g. dual accelerometer.)
|
51 |
|
|
//
|
52 |
|
|
// Operation of this module is very simple:
|
53 |
|
|
//
|
54 |
|
|
// An up-counter (T) counts clocks in one period of the incoming PWM signal.
|
55 |
|
|
// The T counter is reset with each rising edge of the incoming PWM waveform.
|
56 |
|
|
//
|
57 |
|
|
// Another (clock-enabled) up-counter (S) counts the clocks during the time
|
58 |
|
|
// when the PWM signal input is high.
|
59 |
|
|
// The S counter is also reset at the rising edge of the incoming PWM wave.
|
60 |
|
|
//
|
61 |
|
|
// To derive the duty cycle as a fraction, a serial divider calculates S/T.
|
62 |
|
|
//
|
63 |
|
|
// Once the fraction is obtained, the output is presented at "dat_o."
|
64 |
|
|
// The signal "stb_o" (strobe output) indicates that a valid reading is
|
65 |
|
|
// present on the data bus output. The strobe will remain high until the
|
66 |
|
|
// reading is acknowledged by pulsing "ack_i" for one clock cycle.
|
67 |
|
|
//
|
68 |
|
|
// If "stb_o" is tied directly to "ack_i" then each time a new reading is
|
69 |
|
|
// obtained a pulse will be produced at "stb_o" which is one single clock wide.
|
70 |
|
|
//
|
71 |
|
|
// It is important to note that in the absence of any ack_i signal, the unit
|
72 |
|
|
// will hold the contents of the last reading, and any new readings from the
|
73 |
|
|
// PWM device will be missed.
|
74 |
|
|
//
|
75 |
|
|
//---------------------------------------------------------------------------
|
76 |
|
|
|
77 |
|
|
|
78 |
|
|
module pwm_reader (
|
79 |
|
|
clk_i,
|
80 |
|
|
clk_en_i,
|
81 |
|
|
rst_i,
|
82 |
|
|
pwm_signal_i,
|
83 |
|
|
ack_i,
|
84 |
|
|
dat_o,
|
85 |
|
|
stb_o
|
86 |
|
|
);
|
87 |
|
|
|
88 |
|
|
parameter COUNTER_WIDTH_PP = 10; // Size to hold (max_pwm_period)*(Fclk_i)
|
89 |
|
|
parameter DAT_WIDTH_PP = 8; // Size of fraction from divider
|
90 |
|
|
parameter DIV_COUNT_WIDTH_PP = 3; // Must be enough bits to hold the number:
|
91 |
|
|
// DAT_WIDTH_PP-1
|
92 |
|
|
|
93 |
|
|
input clk_i;
|
94 |
|
|
input clk_en_i;
|
95 |
|
|
input rst_i;
|
96 |
|
|
input pwm_signal_i;
|
97 |
|
|
input ack_i;
|
98 |
|
|
|
99 |
|
|
output [DAT_WIDTH_PP-1:0] dat_o;
|
100 |
|
|
output stb_o;
|
101 |
|
|
|
102 |
|
|
// Local signals
|
103 |
|
|
reg [COUNTER_WIDTH_PP-1:0] s_cnt;
|
104 |
|
|
reg [COUNTER_WIDTH_PP-1:0] t_cnt;
|
105 |
|
|
reg pwm_ff_1;
|
106 |
|
|
reg pwm_ff_2;
|
107 |
|
|
reg ack_r;
|
108 |
|
|
|
109 |
|
|
wire rising_edge;
|
110 |
|
|
wire divide_done;
|
111 |
|
|
|
112 |
|
|
//-----------------------------------------------------------------------
|
113 |
|
|
// Try to avoid metastability by running the input signal through
|
114 |
|
|
// a D flip flop.
|
115 |
|
|
always @(posedge clk_i)
|
116 |
|
|
begin
|
117 |
|
|
if (rst_i) pwm_ff_1 <= 0;
|
118 |
|
|
else pwm_ff_1 <= pwm_signal_i;
|
119 |
|
|
end
|
120 |
|
|
|
121 |
|
|
// This is the rising edge detection
|
122 |
|
|
always @(posedge clk_i)
|
123 |
|
|
begin
|
124 |
|
|
if (rst_i) pwm_ff_2 <= 0;
|
125 |
|
|
else pwm_ff_2 <= pwm_ff_1;
|
126 |
|
|
end
|
127 |
|
|
assign rising_edge = pwm_ff_1 && ~pwm_ff_2;
|
128 |
|
|
|
129 |
|
|
// This is period counter
|
130 |
|
|
always @(posedge clk_i)
|
131 |
|
|
begin
|
132 |
|
|
if (rst_i || rising_edge) t_cnt <= 0;
|
133 |
|
|
else if (clk_en_i) t_cnt <= t_cnt + 1;
|
134 |
|
|
end
|
135 |
|
|
|
136 |
|
|
// This is duty cycle counter
|
137 |
|
|
always @(posedge clk_i)
|
138 |
|
|
begin
|
139 |
|
|
if (rst_i || rising_edge) s_cnt <= 0;
|
140 |
|
|
else if (clk_en_i && pwm_signal_i) s_cnt <= s_cnt + 1;
|
141 |
|
|
end
|
142 |
|
|
|
143 |
|
|
// This unit provides for the division s_cnt/t_cnt.
|
144 |
|
|
// The values in the counters are latched into the divider whenever
|
145 |
|
|
// the divide_i input is pulsed.
|
146 |
|
|
// The divider ignores the inputs whenever "divide_i" is not pulsed, so
|
147 |
|
|
// there is no problem with the counters continually advancing until
|
148 |
|
|
// the division is started.
|
149 |
|
|
//
|
150 |
|
|
// Since the result is expected to be purely fractional, the quotient part
|
151 |
|
|
// is all zero, and is thrown away on purpose. (A special divider could be
|
152 |
|
|
// build possibly to avoid this?)
|
153 |
|
|
serial_divide_uu #(
|
154 |
|
|
COUNTER_WIDTH_PP, // M_PP (dividend width)
|
155 |
|
|
COUNTER_WIDTH_PP, // N_PP (divisor width)
|
156 |
|
|
DAT_WIDTH_PP, // R_PP (remainder width)
|
157 |
|
|
COUNTER_WIDTH_PP, // S_PP (skip integer part of quotient)
|
158 |
|
|
DIV_COUNT_WIDTH_PP, // counter bits
|
159 |
|
|
1 // need output holding buffers?
|
160 |
|
|
)
|
161 |
|
|
divider_unit
|
162 |
|
|
(
|
163 |
|
|
.clk_i(clk_i),
|
164 |
|
|
.clk_en_i(1'b1),
|
165 |
|
|
.rst_i(rst_i),
|
166 |
|
|
// New divide is not allowed until previous value is read or acknowledged
|
167 |
|
|
.divide_i(rising_edge && ~stb_o),
|
168 |
|
|
.dividend_i(s_cnt),
|
169 |
|
|
.divisor_i(t_cnt),
|
170 |
|
|
.quotient_o(dat_o),
|
171 |
|
|
.done_o(divide_done)
|
172 |
|
|
);
|
173 |
|
|
|
174 |
|
|
// This latches the ack_i input, so that at least one pulse of stb_o is produced
|
175 |
|
|
// before the ack_i takes it down low again, in case the stb_o output is wired
|
176 |
|
|
// directly to the ack_i input.
|
177 |
|
|
always @(posedge clk_i)
|
178 |
|
|
begin
|
179 |
|
|
if (rst_i || (rising_edge && ~stb_o)) ack_r <= 0;
|
180 |
|
|
else if (stb_o) ack_r <= ack_i;
|
181 |
|
|
end
|
182 |
|
|
|
183 |
|
|
assign stb_o = divide_done && ~ack_r;
|
184 |
|
|
|
185 |
|
|
endmodule
|
186 |
|
|
|
187 |
|
|
|