OpenCores
URL https://opencores.org/ocsvn/quad_decoder/quad_decoder/trunk

Subversion Repositories quad_decoder

[/] [quad_decoder/] [trunk/] [quad_decoder.vhd] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 scottnortm
--------------------------------------------------------------------------------
2 3 scottnortm
--  File:       quad_decoder.vhd
3
--  Desc:       HDL implementation of a quadrature decoder with a Wishbone bus
4
--              interface. See the "quad_decoder" datasheet for more information.
5
--  Date:       Initiated October, 2009
6
--  Auth:       Scott Nortman, COPYRIGHT 2009 Bridge Electronic Design LLC
7
--              scott.nortman@gmail.com
8
--
9
--  NOTE:       If you find this file useful / helpful, please let me know :)
10
--
11 2 scottnortm
--------------------------------------------------------------------------------
12
--
13 3 scottnortm
--      REVISION INFORMATION
14 2 scottnortm
--
15 3 scottnortm
--      Current Version:    1.0.0
16 2 scottnortm
--
17 3 scottnortm
--      Nov. 2009
18
--      1)Initial beta release, upload to OpenCores.org.
19
--      2)Tested HDL implementation with in a Xilinx Spartan 3 AN FPGA, with
20
--      a softcore processor, the Tasking TSK3000.  Emulated a quadrature
21
--      encoder for initial verification.
22 2 scottnortm
--
23 3 scottnortm
--      July, 2010
24
--      1)Release version v1.0.0
25
--      2)Changes from prior release:
26
--      a) Bit 3 of the Quadrature Control Register (offset 0x00) is now changed
27
--      functions, to enable / disable of the Index Zero Count function.  When
28
--      the bit is 0, an index event does not affect the count. When the bit is
29
--      1, and index events are permitted, the internal quadrature count is set
30
--      to 0.
31
--      b) Added control bit 13, Index Read Count Bit.  When set to 0, no count
32
--      is latched. When set to 1, and index events are permitted, the internal
33
--      quadrature count is automatically latched to the QRW (offset 0x08)
34
--      register when an index event is true.  This is VERY useful for detection
35
--      of missed encoder counts, as you can assume that the delta counts in
36
--      between each index event is fixed, so any deviation from the expected
37
--      amount indicates that there were missed encoder counts.
38
--      3)Tested the FPGA implementation with a real encoder, verified proper
39
--      operation with count frequencies up to  1.3MHz (50MHz system clock)
40
--      This test used an instrumented motor driver, with a hardware qudrature
41
--      decoder in parallel with this encoder module.  This module did not miss
42
--      any counts with a 2048 quad counts / rev encoder running at 40e3 rpm.
43
--      4) Fixed a minor bug with the QCR_PLCT bit and the QCR_INZC bit; under
44
--      a specific condition that both the PLCT bit and the INZC bit were asserted
45
--      at the same clock cycle, the PLCT would have been executed while the INZC
46
--      event would have been missed.
47
--      5) Added an additional feature:  Quadrature Count Compare Match Event;
48
--      when the CCME bit is set in the QCR register, and the quadrature count
49
--      matches the QRW register, a signal is asserted and the status bit of the
50
--      QSR register is set.  This event can also generate an interrupt.
51 2 scottnortm
--
52
-------------------------------------------------------------------------------
53
 
54
library ieee;
55
use ieee.std_logic_1164.all;
56
use ieee.std_logic_unsigned.all;
57
 
58
entity quad_decoder is
59
    --Configurable quadrature counter width; default is 32 bits
60
    generic(    QUAD_COUNT_WIDTH    : integer   := 32 );
61
    port(   --Wishbone bus signals
62
            wb_clk_i    : in    std_logic;
63
            wb_rst_i    : in    std_logic;
64
            wb_stb_i    : in    std_logic;
65
            wb_cyc_i    : in    std_logic;
66
            wb_ack_o    : out   std_logic;
67
            --wb_adr_i    : in    std_logic_vector(3 downto 0);
68 3 scottnortm
            wb_adr_i    : in    std_logic_vector(1 downto 0); --assumes 32 bit alignment
69 2 scottnortm
            wb_dat_o    : out   std_logic_vector(31 downto 0);
70
            wb_dat_i    : in    std_logic_vector(31 downto 0);
71
            wb_we_i     : in    std_logic;
72
            --Quadrature inputs
73
            quad_cha_i  : in    std_logic;  --Qudrature channel A
74
            quad_chb_i  : in    std_logic;  --Quadrature channel B
75
            quad_idx_i  : in    std_logic;  --Quadrature index
76
            quad_lat_i  : in    std_logic;  --Quadrature latch cnt input
77
            quad_irq_o  : out   std_logic   --Quadrature IRQ out
78
    );
79
end quad_decoder;
80
 
81
architecture quad_decoder_rtl of quad_decoder is
82
 
83
    --Register and bit definitions
84
   -----------------------------------------------------------------------------
85
   --   Quadrature Control Register, QCR, offset 0x00
86
   --
87 3 scottnortm
   --   Bit 0:  Enable Counting, ECNT
88 2 scottnortm
   --       0 -> Quadrature counting disabled
89
   --       1 -> Quadrature counting enabled
90
   --   Bit 1:  Set Count Direction, CTDR
91
   --       0 -> Counts positive when A leads B
92
   --       1 -> Counts negative when A leads B
93
   --   Bit 2:  Index Enable Bit, INEN
94
   --       0 -> Index input disabled
95
   --       1 -> Index input enabled
96 3 scottnortm
   --   Bit 3:  Index Zero Count Bit, INZC
97 2 scottnortm
   --       0 -> Internal count not affected.
98 3 scottnortm
   --       1 -> Zero internal quad_count when quad_index is asserted.
99 2 scottnortm
   --   Bit 4:  Index Interrupt Enable, INIE
100
   --       0 -> Index interrupt request disabled
101
   --       1 -> Index interrupt request enabled
102
   --   Bit 5:  Pre Load Count register, PLCT
103
   --       0 -> No action.
104
   --       1 -> Load value currently in pre load reg into count reg, auto clear
105
   --   Bit 6:  Underflow Interrupt Enable, UNIE
106
   --       0 -> Underflow event will not trigger an interrupt.
107
   --       1 -> Underflow event will trigger an interrupt
108
   --   Bit 7:  Overflow Interrupt Enable, OVIE
109
   --       0 -> Overflow event will not trigger an interrupt
110
   --       1 -> Overflow event will trigger an interrupt
111
   --   Bit 8:  Quadrature Count Latch, QLAT
112
   --       0 -> No action.
113
   --       1 -> Latch and store quad count in QRW register, auto cleared
114
   --   Bit 9:  Index Channel A configuration, ICHA
115
   --       0 -> Index asserted when quadrature channel A logic low
116
   --       1 -> Index asserted when quadrature channel A logic high
117
   --   Bit 10: Index Channel B configuration, ICHB
118
   --       0 -> Index asserted when quadrature channel B logic low
119
   --       1 -> Index asserted when quadrature channel B logic high
120
   --   Bit 11: Index Level configuration, IDXL
121
   --       0 -> Index asserted when quadature index is logic low
122
   --       1 -> Index asserted when quadrature index is logic high
123
   --   Bit 12: Quadrature Error Interrupt enable, QEIE
124
   --        0 -> Quadrature Error Interrupt disabled
125
   --        1 -> Quadrature Error Interrupt enabled
126 3 scottnortm
   --   Bit 13: Index Read Count Bit, INRC
127
   --        0 -> Quadrature Read / Write register not affected.
128
   --        1 -> Read the value of the quad. count to the QRW reg, when index event is true.
129
   --   Bit 14: Count Compare Match Enable, CCME
130
   --        0 -> No compare match event may occur.
131
   --        1 -> Compare match event asserted when enabled and QRW == quad_count
132
   --   Bit 15:  Compare Match Interrupt Enable, CMIE
133
   --        0 -> No interrupt generated when a compare match event is asserted.
134
   --        1 -> An external interrupt will be generated when the compare event is asserted.
135
   --   Bits 31:16 -> Reserved, must always be written to 0
136 2 scottnortm
   --
137
   -----------------------------------------------------------------------------
138 3 scottnortm
    constant    QCR_ECNT    : integer := 0;
139
    constant    QCR_CTDR    : integer := 1;
140
    constant    QCR_INEN    : integer := 2;
141
    constant    QCR_INZC    : integer := 3;
142
    constant    QCR_INIE    : integer := 4;
143
    constant    QCR_PLCT    : integer := 5;
144
    constant    QCR_UNIE    : integer := 6;
145
    constant    QCR_OVIE    : integer := 7;
146
    constant    QCR_QLAT    : integer := 8;
147
    constant    QCR_ICHA    : integer := 9;
148
    constant    QCR_ICHB    : integer := 10;
149
    constant    QCR_IDXL    : integer := 11;
150
    constant    QCR_QEIE    : integer := 12;
151
    constant    QCR_INRC    : integer := 13;
152
    constant    QCR_CCME    : integer := 14;
153
    constant    QCR_CMIE    : integer := 15;
154
    constant    QCR_BITS    : integer := 16;    --Number of bits used in QCR register
155 2 scottnortm
    signal      qcr_reg     : std_logic_vector(QCR_BITS-1 downto 0);     --QCR register
156 3 scottnortm
    constant    QCR_ADDR    : std_logic_vector(1 downto 0) := "00";
157 2 scottnortm
 
158
    ----------------------------------------------------------------------------
159
    --  Quadrature Status Register, QSR, offset 0x04
160
    --  Note:  User clears set bits by writing a 1 to the correspoding register
161
    --         bit.
162
    --  Bit 0:  Quadrature decoder error status, QERR, auto set, user cleared
163
    --      0 -> No error
164
    --      1 -> Illegal state transition detected
165
    --  Bit 1:  Counter Overflow, CTOV, auto set, user cleared
166
    --      0 -> No overflow detected
167
    --      1 -> Counter overflow from 0xFFFF to 0x0000
168
    --  Bit 2:  Counter Underflow, CTUN, auto set, user cleared
169
    --      0 -> No underflow detected
170
    --      1 -> Counter underflow from 0x0000 to 0xFFFF
171
    --  Bit 3:  Index event, INEV, auto set, user cleared
172
    --      0 -> Index event has not occurred
173
    --      1 -> Index event occured, interrupt requested if INIE set
174 3 scottnortm
    --  Bit 4: Count Compare Match Event, CCME, auto set, user cleared
175
    --      0 -> Compare match event has not occurred
176
    --      1- > Compare match event occurred, interrupt genetated if enabled
177
    --  Bits 31:5   -> Reserved, will always read 0
178 2 scottnortm
    ----------------------------------------------------------------------------
179 3 scottnortm
    constant    QSR_QERR    : integer := 0;
180
    constant    QSR_CTOV    : integer := 1;
181
    constant    QSR_CTUN    : integer := 2;
182
    constant    QSR_INEV    : integer := 3;
183
    constant    QSR_CCME    : integer := 4;
184
    constant    QSR_BITS    : integer := 5;                             -- Num bits in QSR reg
185
    signal      qsr_reg     : std_logic_vector(QSR_BITS-1 downto 0);    --QSR register
186
    constant    QSR_ADDR    : std_logic_vector(1 downto 0) := "01";
187 2 scottnortm
 
188
    --Signals indicating status information for the QSR process
189
    signal      quad_error  : std_logic;
190
    signal      quad_ovflw  : std_logic;
191
    signal      quad_unflw  : std_logic;
192
    signal      quad_index  : std_logic;
193 3 scottnortm
    signal      quad_index_d : std_logic;
194
    signal      quad_index_d2: std_logic;
195
    signal      quad_comp   : std_logic;
196 2 scottnortm
 
197
    ----------------------------------------------------------------------------
198
    --  Quadrature Count Read / Write Register, QRW, offset 0x08
199
    --  Note:   The actual quadrature count value must be latched prior to
200
    --          reading from this register.  This may be triggered two ways:
201
    --          1) Writing a '1' to the QCR, bit 9 quadrature count latch
202
    --              (QLAT), -or-
203
    --          2) Asserting the external syncronous input quad_lat_i.
204
    --          Once either event occurs, the quadrature count value will be
205
    --          copied to the QCT register.
206
    --
207
    --          This register is also used to hold the pre-load count value.
208
    --          After writing to this register, the pre-load value is
209
    --          transferred to the quadrature count register by writing a '1'
210 3 scottnortm
    --          to bit location 5, quadrature pre-load count (PLCT) of the
211 2 scottnortm
    --          quadrature control register (QCR) offset 0x00.
212
    ----------------------------------------------------------------------------
213
    signal      qrw_reg     : std_logic_vector(QUAD_COUNT_WIDTH-1 downto 0);
214 3 scottnortm
    constant    QRW_ADDR    : std_logic_vector(1 downto 0) := "10";
215 2 scottnortm
 
216
    --Actual quadrature counter register, extra bit for over/underflow detect
217
    signal      quad_count  : std_logic_vector(QUAD_COUNT_WIDTH downto 0);
218
 
219
    --Input buffers / filters for quadrature signals
220
    signal      quad_cha_buf: std_logic_vector(3 downto 0);
221
    signal      quad_chb_buf: std_logic_vector(3 downto 0);
222
    signal      quad_idx_buf: std_logic_vector(3 downto 0);
223
    signal      quad_cha_flt: std_logic;
224
    signal      quad_chb_flt: std_logic;
225
    signal      quad_idx_flt: std_logic;
226
    signal      quad_cha_j  : std_logic;
227
    signal      quad_cha_k  : std_logic;
228
    signal      quad_chb_j  : std_logic;
229
    signal      quad_chb_k  : std_logic;
230
    signal      quad_idx_j  : std_logic;
231
    signal      quad_idx_k  : std_logic;
232
 
233 3 scottnortm
    signal      quad_lat_flt : std_logic;
234
    signal      quad_lat_q   : std_logic;
235
    signal      quad_lat_m   : std_logic;
236 2 scottnortm
 
237
    --Quadrature 4X decoding state machine signals
238
    signal      quad_st_new : std_logic_vector(1 downto 0);
239
    signal      quad_st_old : std_logic_vector(1 downto 0);
240
    signal      quad_trans  : std_logic;
241
    signal      quad_dir    : std_logic;
242
    -- State constants for 4x quad decoding, CH B is MSB, CH A is LSB
243
    constant    QUAD_STATE_0: std_logic_vector(1 downto 0) := "00";
244
    constant    QUAD_STATE_1: std_logic_vector(1 downto 0) := "01";
245
    constant    QUAD_STATE_2: std_logic_vector(1 downto 0) := "11";
246
    constant    QUAD_STATE_3: std_logic_vector(1 downto 0) := "10";
247 3 scottnortm
 
248
    --Wishbone internal signals
249
    signal      wb_request  : std_logic;
250
    signal      wb_write    : std_logic;
251
 
252 2 scottnortm
    --Signal for single clock delay of ack out
253 3 scottnortm
    signal      ack_dly     : std_logic;
254
 
255 2 scottnortm
    --Internal irq signal
256
    signal      quad_irq_int: std_logic;
257
 
258 3 scottnortm
    -- Internal signal to latch quad count on index assertion
259
    signal qcnt_idx_latch   : std_logic;
260
 
261 2 scottnortm
    ----------------------------------------------------------------------------
262
    --Start of RTL
263
    ----------------------------------------------------------------------------
264
    begin
265 3 scottnortm
 
266
        --Assign internal signal to external signal
267 2 scottnortm
        quad_irq_o  <= quad_irq_int;
268
 
269
        -- Handle wishbone ack generation / internal write signals
270
        wb_request  <= wb_stb_i and wb_cyc_i;
271
        wb_write    <= wb_request and wb_we_i;
272 3 scottnortm
        wb_ack_o    <= ack_dly;
273
 
274
        -----------------------------------------------------------------------
275
        --  Process:    qck_dly_proc( wb_clk_i )
276
        --  Desc:       Generates the wishbone ack signal after a single clock
277
        --              delay.  This insures that the internal read / write
278
        --              operations have completed before acknowledging the
279
        --              master device.
280
        --  Signals:    wb_clk_i
281
        --              ack_dly
282
        --              wb_rst_i
283
        --  Notes:      Verified using the Wishbone bus of the TSK3000 from
284
        --              Altium Designer.
285
        -----------------------------------------------------------------------
286 2 scottnortm
        ack_dly_proc: process( wb_clk_i ) begin
287
            if rising_edge( wb_clk_i ) then
288
                if wb_rst_i = '1' then
289
                    ack_dly <= '0';
290
                elsif wb_request = '1' then
291
                    ack_dly <= '1';
292
                end if;
293
                if ack_dly = '1' then
294
                    ack_dly <= '0';
295
                end if;
296
            end if;
297
        end process ack_dly_proc;
298
 
299
        -----------------------------------------------------------------------
300
        --  Process:    qcr_reg_wr_proc( wb_clk_i )
301
        --  Desc:       Handles writing of the Quadrature Control Regsiter
302
        --              signal, address offset 0x00.
303
        --  Signals:    qcr_reg, quadrature control register
304
        --              wb_rst_i, external reset input
305
        --              wb_write, internal write enable signal
306
        --              wb_adr_i, wishbone address inputs
307
        --              wb_dat_i, wishbone data inputs
308
        --  Notes:      See comments above for more info re the qcr_reg
309
        -----------------------------------------------------------------------
310
        qcr_reg_wr_proc: process( wb_clk_i ) begin
311
            if rising_edge( wb_clk_i ) then
312
                if wb_rst_i = '1' then
313
                    qcr_reg <= (others => '0');
314 3 scottnortm
                elsif wb_write = '1' and wb_adr_i = QCR_ADDR then
315 2 scottnortm
                    qcr_reg <= wb_dat_i(QCR_BITS-1 downto 0);
316
                end if;
317
                --See if PLCT asserted, should be auto-cleared
318
                if qcr_reg(QCR_PLCT) = '1' then
319
                    qcr_reg(QCR_PLCT) <= '0';
320
                end if;
321
                --See if QLAT asserted, should be auto-cleared
322
                if qcr_reg(QCR_QLAT) = '1' then
323
                    qcr_reg(QCR_QLAT) <= '0';
324
                end if;
325
            end if;
326
        end process qcr_reg_wr_proc;
327
 
328
        -----------------------------------------------------------------------
329
        --  Process:    qsr_reg_wr_proc( wb_clk_i )
330 3 scottnortm
        --  Desc:       Handles writing of the Quadrature Status Register, QSR,
331 2 scottnortm
        --              offset 0x04.
332
        --  Signals:    quad_error, internal error status signal
333
        --              quad_ovflw, internal counter overflow signal
334
        --              quad_unflw, internal counter underflow signal
335
        --              quad_index, internl index event signal
336
        --              wb_rst_i, external reset input
337
        --              wb_write, internal write enable signal
338
        --              wb_adr_i, wishbone address inputs
339
        --              wb_dat_i, wishbone data inputs
340
        --  Notes:      All of these bits are set automatically based on the
341
        --              states of the internal signals.  Once set, the user must
342
        --              write a '1' to the corresponding bit location to clear it.
343
        --              See the comments above for more information.
344
        -----------------------------------------------------------------------
345
        qsr_reg_wr_proc: process( wb_clk_i ) begin
346
            if rising_edge( wb_clk_i ) then
347
                if wb_rst_i = '1' then
348
                    qsr_reg     <= (others => '0');
349
                else
350
                    --Set qsr_reg bit from signal quad_error
351 3 scottnortm
                    if quad_error = '1' and qcr_reg(QCR_ECNT) = '1' then
352 2 scottnortm
                        qsr_reg(QSR_QERR) <= '1';
353 3 scottnortm
                    elsif wb_write = '1' and wb_adr_i = QSR_ADDR and qsr_reg(QSR_QERR) = '1' and wb_dat_i(QSR_QERR) = '1' then
354 2 scottnortm
                        qsr_reg(QSR_QERR) <= '0';
355
                    end if;
356
                    --Set qsr_reg bit rom signal quad_ovflw
357 3 scottnortm
                    if quad_ovflw = '1' then
358 2 scottnortm
                        qsr_reg(QSR_CTOV) <= '1';
359 3 scottnortm
                    elsif wb_write = '1' and wb_adr_i = QSR_ADDR and qsr_reg(QSR_CTOV) = '1' and wb_dat_i(QSR_CTOV) = '1' then
360 2 scottnortm
                        qsr_reg(QSR_CTOV) <= '0';
361
                    end if;
362
                    --Set qsr_reg bit from signal quad_unflw
363 3 scottnortm
                    if quad_unflw = '1' then
364 2 scottnortm
                        qsr_reg(QSR_CTUN) <= '1';
365 3 scottnortm
                    elsif wb_write = '1' and wb_adr_i = QSR_ADDR and qsr_reg(QSR_CTUN) = '1' and wb_dat_i(QSR_CTUN) = '1' then
366 2 scottnortm
                        qsr_reg(QSR_CTUN) <= '0';
367
                    end if;
368
                    --Set qsr_reg bit from signal quad_index
369 3 scottnortm
                    if quad_index = '1' then
370 2 scottnortm
                        qsr_reg(QSR_INEV) <= '1';
371 3 scottnortm
                    elsif wb_write = '1' and wb_adr_i = QSR_ADDR and qsr_reg(QSR_INEV) = '1' and wb_dat_i(QSR_INEV) = '1' then
372 2 scottnortm
                        qsr_reg(QSR_INEV) <= '0';
373
                    end if;
374 3 scottnortm
                    --check quadrature compare bit
375
                    if quad_comp = '1' then
376
                        qsr_reg(QSR_CCME) <= '1';
377
                    elsif wb_write = '1' and wb_adr_i = QSR_ADDR and qsr_reg(QSR_CCME) = '1' and wb_dat_i(QSR_CCME) = '1' then
378
                        qsr_reg(QSR_CCME) <= '0';
379
                    end if;
380 2 scottnortm
                end if;
381
            end if;
382
        end process qsr_reg_wr_proc;
383 3 scottnortm
 
384 2 scottnortm
        -----------------------------------------------------------------------
385
        --  Process:    qrw_reg_wr_proc( wb_clk_i )
386
        --  Desc:       Handles writing to the Quadrature Read / Write Register,
387
        --              offset 0x08.
388 3 scottnortm
        --  Signals:    wb_rst, reset signal
389
        --              QLAT bit of QCR reg, Quadrature latch
390
        --              quad_lat_flt, filtered external quadrature latch signal
391
        --  Notes:      Use of this register is required to access the
392
        --              quadrature count.
393 2 scottnortm
        -----------------------------------------------------------------------
394
        qrw_reg_wr_proc: process( wb_clk_i ) begin
395
            if rising_edge( wb_clk_i ) then
396
                if wb_rst_i = '1' then
397
                    qrw_reg <= (others =>'0');
398 3 scottnortm
                elsif wb_write = '1' and wb_adr_i = QRW_ADDR then
399 2 scottnortm
                    qrw_reg <= wb_dat_i;
400 3 scottnortm
                elsif qcr_reg(QCR_QLAT) = '1' or quad_lat_flt = '1' or (qcr_reg(QCR_INRC) = '1' and quad_index = '1') then
401 2 scottnortm
                    qrw_reg <= quad_count(QUAD_COUNT_WIDTH-1 downto 0);
402 3 scottnortm
                end if;
403 2 scottnortm
            end if;
404
        end process qrw_reg_wr_proc;
405 3 scottnortm
 
406 2 scottnortm
        -----------------------------------------------------------------------
407
        --  Process:    quad_regs_rd_proc( wb_clk_i )
408
        --  Desc:       Handles reading of all of the registers.
409 3 scottnortm
        --  Signals:    wb_adr_i, Wishbone address input
410
        --              qcr_reg, Quadrature control register
411
        --              qsr_reg, Quadrature status register
412
        --              qrw_reg, Quadrature read/write register
413
        --  Notes:      None.
414 2 scottnortm
        -----------------------------------------------------------------------
415 3 scottnortm
        quad_regs_rd_proc: process( wb_adr_i, qcr_reg, qsr_reg, qrw_reg ) begin
416
            case wb_adr_i is
417
                when QCR_ADDR   =>
418
                    wb_dat_o(QCR_BITS-1 downto 0) <= qcr_reg;
419
                    wb_dat_o(31 downto QCR_BITS) <= (others => '0');
420
                when QSR_ADDR   =>
421
                    wb_dat_o(QSR_BITS-1 downto 0) <= qsr_reg;
422
                    wb_dat_o(31 downto QSR_BITS) <= (others => '0');
423
                when QRW_ADDR   =>
424
                    wb_dat_o(QUAD_COUNT_WIDTH-1 downto 0) <= qrw_reg;
425
                when others =>
426
                    wb_dat_o    <= (others => '0' );
427
            end case;
428 2 scottnortm
        end process quad_regs_rd_proc;
429 3 scottnortm
 
430
        -----------------------------------------------------------------------
431
        --  Process:    quad_lat_m_proc( wb_clk_i )
432
        --  Desc:       Rising edge detect for input quad_lat_i
433
        --  Signals:    quad_lat_i, external quadratire latch input
434
        --              quad_lat_m, metastable quadature latch signal
435
        --  Note:       This is an asynchronous signal; the metastable
436
        --              output is later latched to a synchronized internal
437
        --              signal for other module processes.
438
        -----------------------------------------------------------------------
439
        quad_lat_m_proc : process( quad_lat_i ) begin
440
            if rising_edge( quad_lat_i ) then
441
                if wb_rst_i = '1' then
442
                    quad_lat_m <= '0';
443
                else
444
                    quad_lat_m <= '1';
445
                end if;
446
 
447
                if quad_lat_m = '1' then
448
                    quad_lat_m  <= '0';
449
                end if;
450
            end if;
451
        end process quad_lat_m_proc;
452
 
453
        -----------------------------------------------------------------------
454
        --  Process:    quad_lat_proc
455
        --  Desc:       Metastable filter for quad_lat_i, sets internal signal
456
        --  Signals:    quad_lat_m, metastable latch signal
457
        --              quad_lat_q, stable latched signal
458
        --              quad_lat_flt, filtered signal used by other processe
459
        --  Note:       Due to the filtering, there is a delay of 4 clk cycles
460
        --              from assertion of the signal until asserting internal
461
        --              processes.
462
        -----------------------------------------------------------------------
463 2 scottnortm
        quad_lat_proc: process( wb_clk_i) begin
464
            if rising_edge( wb_clk_i ) then
465
                if wb_rst_i = '1' then
466
                    quad_lat_flt    <= '0';
467 3 scottnortm
                    quad_lat_q      <= '0';
468 2 scottnortm
                else
469 3 scottnortm
                    if quad_lat_m = '1' then
470
                        quad_lat_q  <= '1';
471
                    end if;
472
                    if quad_lat_q = '1' then
473
                        quad_lat_q      <= '0';
474
                        quad_lat_flt    <= '1';
475
                    end if;
476 2 scottnortm
                    if quad_lat_flt = '1' then
477
                        quad_lat_flt <= '0';
478
                    end if;
479
                end if;
480
            end if;
481
        end process quad_lat_proc;
482
 
483
        --Combinatorial logic for JK flip flop filters
484
        quad_cha_j  <= quad_cha_buf(3) and quad_cha_buf(2) and quad_cha_buf(1);
485
        quad_cha_k  <= not( quad_cha_buf(3) or quad_cha_buf(2) or quad_cha_buf(1) );
486
        quad_chb_j  <= quad_chb_buf(3) and quad_chb_buf(2) and quad_chb_buf(1);
487
        quad_chb_k  <= not( quad_chb_buf(3) or quad_chb_buf(2) or quad_chb_buf(1) );
488
        quad_idx_j  <= quad_idx_buf(3) and quad_idx_buf(2) and quad_idx_buf(1);
489
        quad_idx_k  <= not( quad_idx_buf(3) or quad_idx_buf(2) or quad_idx_buf(1) );
490 3 scottnortm
 
491
        -----------------------------------------------------------------------
492
        --  Process:    quad_filt_proc
493
        --  Desc:       Digital filters for the quadrature inputs.  This is
494
        --              implemented with serial shift registers on all inputs;
495
        --              similar to the digital filters of the HCTL-2016.  See
496
        --              that datasheet for more information.
497
        --  Signals:    quad_cha_i, external input
498
        --              quad_chb_i, external input
499
        --              quad_idx_i, external input
500
        --              quad_cha_buf, input buffer for filtering
501
        --              quad_chb_buf, input buffer for filtering
502
        --              quad_cha_flt, filtered cha signal
503
        --              quad_chb_flt, filtered chb signal
504
        --              quad_cha_j, j signal for jk FF
505
        --              quad_cha_k, k signal for jk FF
506
        --  Note:       Upon reset, all buffers are filled with the values
507
        --              present on the input pins.
508
        -----------------------------------------------------------------------
509 2 scottnortm
        quad_filt_proc: process( wb_clk_i ) begin
510
            if rising_edge( wb_clk_i ) then
511
                if wb_rst_i = '1' then
512
                    quad_cha_buf    <= ( quad_cha_i & quad_cha_i & quad_cha_i & quad_cha_i );
513
                    quad_chb_buf    <= ( quad_chb_i & quad_chb_i & quad_chb_i & quad_chb_i );
514
                    quad_idx_buf    <= ( quad_idx_i & quad_idx_i & quad_idx_i & quad_idx_i );
515
                    quad_cha_flt    <= quad_cha_i;
516
                    quad_chb_flt    <= quad_chb_i;
517
                    quad_idx_flt    <= quad_idx_i;
518
                else
519
                    --sample inputs, place into shift registers
520
                    quad_cha_buf    <= ( quad_cha_buf(2) & quad_cha_buf(1) & quad_cha_buf(0) & quad_cha_i );
521
                    quad_chb_buf    <= ( quad_chb_buf(2) & quad_chb_buf(1) & quad_chb_buf(0) & quad_chb_i );
522
                    quad_idx_buf    <= ( quad_idx_buf(2) & quad_idx_buf(1) & quad_idx_buf(0) & quad_idx_i );
523
 
524
                    -- JK flip flop filters
525
                    if quad_cha_j = '1' then
526
                        quad_cha_flt    <= '1';
527
                    end if;
528
                    if quad_cha_k = '1' then
529
                        quad_cha_flt    <= '0';
530
                    end if;
531
                    if quad_chb_j = '1' then
532
                        quad_chb_flt    <= '1';
533
                    end if;
534
                    if quad_chb_k = '1' then
535
                        quad_chb_flt    <= '0';
536
                    end if;
537
                    if quad_idx_j = '1' then
538
                        quad_idx_flt <= '1';
539
                    end if;
540
                    if quad_idx_k = '1' then
541
                        quad_idx_flt <= '0';
542 3 scottnortm
                    end if;
543 2 scottnortm
                end if;
544
            end if;
545
        end process quad_filt_proc;
546
 
547
        -----------------------------------------------------------------------
548 3 scottnortm
        --  Process:    quad_state_proc
549
        --  Desc:       Reads filtered values quad_cha_flt, quad_chb_flt and
550
        --              asserts the quad_trans and quad_dir signals.
551
        --  Signals:    quad_st_old
552
        --              quad_st_new
553
        --              quad_trans
554
        --              quad_dir
555
        --              quad_error
556
        --  Notes:      See the datasheet for more info.
557
        -----------------------------------------------------------------------
558 2 scottnortm
        quad_state_proc: process( wb_clk_i ) begin
559
            if rising_edge( wb_clk_i ) then
560
                if wb_rst_i = '1' then
561
                    quad_st_old     <= (quad_chb_i & quad_cha_i);
562
                    quad_st_new     <= (quad_chb_i & quad_cha_i);
563
                    quad_trans      <= '0';
564
                    quad_dir        <= '0';
565
                    quad_error      <= '0';
566 3 scottnortm
                else
567 2 scottnortm
                    quad_st_new <= (quad_chb_flt & quad_cha_flt);
568
                    quad_st_old <= quad_st_new;
569 3 scottnortm
                    --state machine enabled if counting
570
                    if qcr_reg(QCR_ECNT) = '1' then
571
                        case quad_st_new is
572
                            when QUAD_STATE_0 =>    --"00"
573
                                case quad_st_old is
574
                                    when QUAD_STATE_0 =>
575
                                        quad_trans      <= '0';
576
                                    when QUAD_STATE_3 => --"10" -- dflt positive direction
577
                                        if qcr_reg(QCR_CTDR) = '1' then
578
                                            quad_trans  <= '1';
579
                                            quad_dir    <= '0';
580
                                        else
581
                                            quad_trans  <= '1';
582
                                            quad_dir    <= '1';
583
                                        end if;
584
                                    when QUAD_STATE_1 => --"01" -- dflt negative direction
585
                                        if qcr_reg(QCR_CTDR) = '1' then
586
                                            quad_trans  <= '1';
587
                                            quad_dir    <= '1';
588
                                        else
589
                                            quad_trans  <= '1';
590
                                            quad_dir    <= '0';
591
                                        end if;
592
                                    when others =>
593
                                        quad_error  <= '1';
594
                                        quad_trans  <= '0';
595
                                end case; --quad_st_old
596 2 scottnortm
 
597 3 scottnortm
                            when QUAD_STATE_1 =>    --"01"
598
                                case quad_st_old is
599
                                    when QUAD_STATE_1 =>
600
                                        quad_trans      <= '0';
601
                                    when QUAD_STATE_0 => --"10" -- dflt positive direction
602
                                        if qcr_reg(QCR_CTDR) = '1' then
603
                                            quad_trans  <= '1';
604
                                            quad_dir    <= '0';
605
                                        else
606
                                            quad_trans  <= '1';
607
                                            quad_dir    <= '1';
608
                                        end if;
609
                                    when QUAD_STATE_2 => --"01" -- dflt negative direction
610
                                        if qcr_reg(QCR_CTDR) = '1' then
611
                                            quad_trans  <= '1';
612
                                            quad_dir    <= '1';
613
                                        else
614
                                            quad_trans  <= '1';
615
                                            quad_dir    <= '0';
616
                                        end if;
617
                                    when others =>
618
                                        quad_error  <= '1';
619
                                        quad_trans  <= '0';
620
                                end case; --quad_st_old
621 2 scottnortm
 
622 3 scottnortm
                            when QUAD_STATE_2 =>    --"11"
623
                                case quad_st_old is
624
                                    when QUAD_STATE_2 =>
625
                                        quad_trans      <= '0';
626
                                    when QUAD_STATE_1 => --"10" -- dflt positive direction
627
                                        if qcr_reg(QCR_CTDR) = '1' then
628
                                            quad_trans  <= '1';
629
                                            quad_dir    <= '0';
630
                                        else
631
                                            quad_trans  <= '1';
632
                                            quad_dir    <= '1';
633
                                        end if;
634
                                    when QUAD_STATE_3 => --"01" -- dflt negative direction
635
                                        if qcr_reg(QCR_CTDR) = '1' then
636
                                            quad_trans  <= '1';
637
                                            quad_dir    <= '1';
638
                                        else
639
                                            quad_trans  <= '1';
640
                                            quad_dir    <= '0';
641
                                        end if;
642
                                    when others =>
643
                                        quad_error  <= '1';
644
                                        quad_trans  <= '0';
645
                                end case; --quad_st_old
646 2 scottnortm
 
647 3 scottnortm
                            when QUAD_STATE_3 =>    --"10"
648
                                case quad_st_old is
649
                                    when QUAD_STATE_3 =>
650
                                        quad_trans      <= '0';
651
                                    when QUAD_STATE_2 => --"10" -- dflt positive direction
652
                                        if qcr_reg(QCR_CTDR) = '1' then
653
                                            quad_trans  <= '1';
654
                                            quad_dir    <= '0';
655
                                        else
656
                                            quad_trans  <= '1';
657
                                            quad_dir    <= '1';
658
                                        end if;
659
                                    when QUAD_STATE_0 => --"01" -- dflt negative direction
660
                                        if qcr_reg(QCR_CTDR) = '1' then
661
                                            quad_trans  <= '1';
662
                                            quad_dir    <= '1';
663
                                        else
664
                                            quad_trans  <= '1';
665
                                            quad_dir    <= '0';
666
                                        end if;
667
                                    when others =>
668
                                        quad_error  <= '1';
669
                                        quad_trans  <= '0';
670
                                end case; --quad_st_old
671 2 scottnortm
 
672 3 scottnortm
                            when others =>
673
                                quad_error  <= '1';
674
                                quad_trans  <= '0';
675
                        end case; --quad_st_new
676
 
677
                    end if;
678
 
679 2 scottnortm
                    if quad_trans = '1' then
680
                        quad_trans  <= '0';
681
                    end if;
682 3 scottnortm
 
683 2 scottnortm
                    if quad_dir = '1' then
684
                        quad_dir    <= '0';
685
                    end if;
686 3 scottnortm
 
687 2 scottnortm
                    if quad_error = '1' then
688
                        quad_error  <= '0';
689
                    end if;
690
                end if;
691
            end if;
692
        end process quad_state_proc;
693 3 scottnortm
 
694 2 scottnortm
        -----------------------------------------------------------------------
695
        --  Process:    quad_count_proc( wb_clk_i )
696 3 scottnortm
        --  Desc:       Handles writing to the quad_count register.
697 2 scottnortm
        --              First, pre-load events are handled; this may be triggered
698
        --              by writing a '1' to the qcr_reg QCR_PLCT bit location, or
699
        --              by an index_event assertion. Next, count events may be
700 3 scottnortm
        --              triggered by an assertion of the 'quad_trans' signal,
701 2 scottnortm
        --              which causes the quad_count value to increment or
702
        --              decrement by one, based on the quad_dir signal.
703 3 scottnortm
        --              With each change on the count value, the counter is
704
        --              checked for over/underflow.  If either is detected, the
705 2 scottnortm
        --              corresponding signal is asserted for one clock cycle.
706
        --  Signals:    quad_count, QUAD_COUNT_WIDTH+1 bit length, holds the actual
707
        --                  4x quadrature counts.  The extra bit (i.e., as compared
708
        --                  to the user register qrw_reg) is for over / underflow
709
        --                  detection.  2's complement integer.
710
        --              quad_ovflw, single bit signal indicating an overflow event
711
        --                  has occurred; asserted one clock cycle then cleared.
712
        --              quad_unflw, single bit signal indicating that an underflow
713
        --                  event occured; asserted one clock cycle then cleared.
714
        --  Note:       See the comments for the qcr_reg register for more info
715
        --              regarding the index event control bits.
716
        -----------------------------------------------------------------------
717
        quad_count_proc: process( wb_clk_i ) begin
718
            if rising_edge( wb_clk_i ) then
719
                --Reset event
720
                if wb_rst_i = '1' then
721
                    quad_count  <= (others =>'0');
722
                    quad_ovflw  <= '0';
723
                    quad_unflw  <= '0';
724 3 scottnortm
                else
725 2 scottnortm
                --Pre-load count event; either from qcr_reg or index event
726 3 scottnortm
                    if qcr_reg(QCR_PLCT) = '1' then
727
                        quad_count(QUAD_COUNT_WIDTH-1 downto 0) <= qrw_reg;
728
                        quad_count(QUAD_COUNT_WIDTH)            <= '0';
729
                    end if;
730
                    if (quad_index = '1' and qcr_reg(QCR_INZC) = '1') then
731
                        quad_count  <= (others =>'0');
732
                    end if;
733
                    if quad_trans = '1' then
734 2 scottnortm
                        if quad_dir = '1' then
735
                            quad_count  <= quad_count + 1;
736
                        else
737
                            quad_count  <= quad_count - 1;
738
                        end if;
739
                    end if;
740
                    --check for over/under flow
741
                    if quad_count(QUAD_COUNT_WIDTH) = '1' then
742
                        --reset overflow bit
743
                        quad_count(QUAD_COUNT_WIDTH)    <= '0';
744
                        --Check MSB-1 to see if it is under or over flow
745
                        if quad_count(QUAD_COUNT_WIDTH-1) = '1' then
746
                            quad_unflw  <= '1';
747
                        else
748
                            quad_ovflw  <= '1';
749
                        end if;
750
                    end if;
751
                end if;
752 3 scottnortm
                --reset signals
753
                if quad_ovflw = '1' then
754
                    quad_ovflw  <= '0';
755
                end if;
756
                if quad_unflw = '1' then
757
                    quad_unflw  <= '0';
758
                end if;
759 2 scottnortm
            end if;
760
        end process quad_count_proc;
761
 
762
        -----------------------------------------------------------------------
763 3 scottnortm
        --  Preocess:   quad_comp_proc( wb_clk_i )
764
        --  Desc:       Monitors the quad_count and the qwr_reg to assert the
765
        --              the quad_comp signal.
766
        --  Signals:    wb_clk_i
767
        --              wb_rst_i
768
        --              quad_comp
769
        --  Note:       When enabled, the quad_comp signal will get asserted
770
        --              every time the quad_count is latched into the qrw reg.
771
        -----------------------------------------------------------------------
772
        quad_comp_proc : process( wb_clk_i ) begin
773
            if rising_edge( wb_clk_i ) then
774
                if wb_rst_i = '1' then
775
                    quad_comp <= '0';
776
                elsif (quad_count(QUAD_COUNT_WIDTH-1 downto 0) = qrw_reg) and qcr_reg(QCR_CCME) = '1' and qsr_reg(QSR_CCME) = '0' then
777
                    quad_comp <= '1';
778
                end if;
779
                if quad_comp = '1' then
780
                    quad_comp <= '0';
781
                end if;
782
            end if;
783
        end process quad_comp_proc;
784
 
785
        -----------------------------------------------------------------------
786 2 scottnortm
        --  Process:    quad_index_proc( wb_clk_i )
787 3 scottnortm
        --  Desc:       Controls the internal quad_index signal.  This signal is
788 2 scottnortm
        --              asserted to indicated the occurance of an index event.
789 3 scottnortm
        --  Signals:    quad_index
790
        --              quad_cha_flt
791
        --              quad_chb_flt
792
        --              quad_index
793
        --  Note:       None.
794 2 scottnortm
        -----------------------------------------------------------------------
795
        quad_index_proc : process( wb_clk_i ) begin
796
            if rising_edge( wb_clk_i ) then
797
                if wb_rst_i = '1' then
798
                    quad_index <= '0';
799 3 scottnortm
                elsif qcr_reg(QCR_INEN) = '1'
800
                    and qcr_reg(QCR_ECNT) = '1'
801
                    and qcr_reg(QCR_ICHA) = quad_cha_flt
802
                    and qcr_reg(QCR_ICHB) = quad_chb_flt
803
                    and qcr_reg(QCR_IDXL) = quad_idx_flt then
804
                    quad_index_d  <= '1';
805 2 scottnortm
                end if;
806 3 scottnortm
                if quad_index_d = '1' then
807
                    quad_index_d <= '0';
808
                    quad_index_d2<= '1';
809
                end if;
810
                if quad_index_d2 ='1' then
811
                    quad_index_d2 <= '0';
812
                    quad_index <= '1';
813
                end if;
814 2 scottnortm
                if quad_index = '1' then
815
                    quad_index <= '0';
816
                end if;
817
            end if;
818
        end process quad_index_proc;
819 3 scottnortm
 
820
        -----------------------------------------------------------------------
821
        --  Process:    quad_irq_proc
822
        --  Desc:       Handles writing to the internal signal quad_irq_int.
823
        --              This process checks to see if a valid interrupt signal
824
        --              is asserted along with the corresponding enable bit; if
825
        --              so, the external interrupt is asserted.
826
        --  Signals:    quad_irq_int
827
        --              quad_error
828
        --              quad_ovflw
829
        --              quad_unflw
830
        --              quad_index
831
        --              quad_comp
832
        --  Note:       The external interrupt is cleared after assertion when
833
        --              all status bits are cleared in the QSR register.
834
        --
835
        -----------------------------------------------------------------------
836 2 scottnortm
        quad_irq_proc: process( wb_clk_i ) begin
837
            if rising_edge( wb_clk_i ) then
838
                if wb_rst_i = '1' then
839
                    quad_irq_int  <= '0';
840
                elsif       ( quad_error = '1' and qcr_reg(QCR_QEIE) = '1' )
841 3 scottnortm
                        or  ( quad_ovflw = '1' and qcr_reg(QCR_OVIE) = '1' )
842
                        or  ( quad_unflw = '1' and qcr_reg(QCR_UNIE) = '1' )
843
                        or  ( quad_index = '1' and qcr_reg(QCR_INIE) = '1' )
844
                        or  ( quad_comp  = '1' and qcr_reg(QCR_CMIE) = '1' ) then
845 2 scottnortm
                    quad_irq_int <= '1';
846 3 scottnortm
                elsif quad_irq_int = '1' and
847 2 scottnortm
                    not(    ( qsr_reg(QSR_QERR) = '1' and qcr_reg(QCR_QEIE) = '1' )
848 3 scottnortm
                        or  ( qsr_reg(QSR_CTOV) = '1' and qcr_reg(QCR_OVIE) = '1' )
849
                        or  ( qsr_reg(QSR_CTUN) = '1' and qcr_reg(QCR_UNIE) = '1' )
850
                        or  ( qsr_reg(QSR_INEV) = '1' and qcr_reg(QCR_INIE) = '1' )
851
                        or  ( qsr_reg(QSR_CCME) = '1' and qcr_reg(QCR_CMIE) = '1' ) ) then
852 2 scottnortm
                    quad_irq_int <= '0';
853
                end if;
854
            end if;
855
        end process quad_irq_proc;
856
 
857
end architecture quad_decoder_rtl;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.