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

Subversion Repositories p9813_rgb_led_string_driver

[/] [p9813_rgb_led_string_driver/] [trunk/] [rtl/] [VHDL/] [signal_conditioning_pack.vhd] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 jclaytons
--------------------------------------------------------------------------
2
-- Package
3
--
4
--
5
 
6
library IEEE;
7
use IEEE.STD_LOGIC_1164.ALL;
8
use IEEE.NUMERIC_STD.ALL;
9
use IEEE.MATH_REAL.ALL;
10
 
11
package signal_conditioning_pack is
12
 
13
-- Component declarations not provided any more.
14
-- With VHDL '93 and newer, component declarations are allowed,
15
-- but not required.
16
--
17
-- Please to try direct instantiation instead, for example:
18
--
19
--   instance_name : entity work.entity_name(beh)
20
--
21
 
22
end signal_conditioning_pack;
23
 
24
-------------------------------------------------------------------------------
25
-- Edge Detector
26
-------------------------------------------------------------------------------
27
--
28
-- Author: John Clayton
29
-- Date  : Nov.  1, 2013 Started Coding, drawing from various other sources.
30
--                       Created description.  Simulated it and saw that it
31
--                       works.
32
--                 
33
--
34
-- Description
35
-------------------------------------------------------------------------------
36
-- This module is a super simple edge detector, which produces is high-going
37
-- pulse whenever there is an edge on the input.  The type of edge is
38
-- selectable via generic.
39
--
40
-- The sys_clk_en affects the operation by extending the length of the pulse
41
-- output beyond one single sys_clk cycle, as expected.
42
--
43
-- Detecting both rising and falling edges is allowed.  Detecting neither is
44
-- also allowed, but not recommended.
45
--
46
-- The sys_rst_n input is an asynchronous reset.
47
 
48
library IEEE;
49
use IEEE.STD_LOGIC_1164.ALL;
50
use IEEE.NUMERIC_STD.ALL;
51
use IEEE.MATH_REAL.ALL;
52
 
53
  entity edge_detector is
54
    generic(
55
      DETECT_RISING  : natural := 1;
56
      DETECT_FALLING : natural := 0
57
    );
58
    port (
59
      -- System Clock and Clock Enable
60
      sys_rst_n   : in  std_logic;
61
      sys_clk     : in  std_logic;
62
      sys_clk_en  : in  std_logic;
63
 
64
      -- Input Signal
65
      sig_i       : in  std_logic;
66
 
67
      -- Output pulse
68
      pulse_o     : out std_logic
69
 
70
    );
71
  end edge_detector;
72
 
73
architecture beh of edge_detector is
74
 
75
  -- Constants
76
 
77
  -- Functions & associated types
78
 
79
  -- Signal Declarations
80
  signal sig_r1  : std_logic;
81
  signal pulse_r : std_logic;
82
  signal pulse_f : std_logic;
83
  signal pulse_b : std_logic;
84
 
85
begin
86
 
87
process (sys_clk, sys_rst_n)
88
begin
89
  if (sys_rst_n='0') then
90
    sig_r1 <= '0';
91
  elsif (sys_clk'event and sys_clk='1') then -- rising edge
92
    if (sys_clk_en='1') then
93
      sig_r1 <= sig_i;
94
    end if;
95
  end if;
96
end process;
97
 
98
-- The detection
99
pulse_r <= '1' when sig_i='1' and sig_r1='0' else '0';
100
pulse_f <= '1' when sig_i='0' and sig_r1='1' else '0';
101
pulse_b <= sig_i xor sig_r1;
102
 
103
-- The output
104
pulse_o <= pulse_b when DETECT_RISING/=0 and DETECT_FALLING/=0 else
105
           pulse_r when DETECT_RISING/=0 else
106
           pulse_f when DETECT_FALLING/=0 else
107
           '0'; -- Haha!  Don't go there!
108
 
109
end beh;
110
 
111
-------------------------------------------------------------------------------
112
-- Leaky Integrator
113
-------------------------------------------------------------------------------
114
--
115
-- Author: John Clayton
116
-- Date  : Oct. 11, 2013 Started Coding, drawing from various other sources.
117
--                       Created description.  Simulated it and saw that it
118
--                       works.
119
--         Sep. 20, 2017 Revised delta assignment, to eliminate custom
120
--                       resize function.
121
--
122
-- Description
123
-------------------------------------------------------------------------------
124
-- This module is a pretty simple digital "leaky integrator" designed to low
125
-- pass noisy signals by integrating them.
126
--
127
--   The first order differential equation is of the form:
128
--
129
--     dx/dt = -leak_factor*x + input
130
--
131
-- The input is discretized in both time and amplitude.  A one bit digital
132
-- input can be mapped to the "input" signal by using a positive value for
133
-- '1' and a negative value for '0'  Alternately, a signed DSP type signal
134
-- can be used directly.
135
--
136
-- The "leak_factor" is a feedback term, so that "DC gain" is inversely
137
-- proportional to the leak_factor.
138
--
139
-- Due to the presence of the feedback term, the integration's DC value, or
140
-- constant term, gets "leaked" to zero over time.  This is nice because
141
-- the threshold centers around zero.
142
--
143
-- Hysteresis can be added so that the digital output transitions an amount
144
-- above or below zero, depending on the current value of the output.
145
--
146
-- Clear as mud?  Well, it's similar to a low-pass filter, and the hysteresis
147
-- also helps remove noise on the input signal.
148
--
149
-- The sys_rst_n input is an asynchronous reset.
150
 
151
library IEEE;
152
use IEEE.STD_LOGIC_1164.ALL;
153
use IEEE.NUMERIC_STD.ALL;
154
use IEEE.MATH_REAL.ALL;
155
 
156
  entity leaky_integrator is
157
    generic(
158
      LEAK_FACTOR_BITS : natural := 10;
159
      LEAK_FACTOR      : natural := 10;
160
      INTEGRATOR_BITS  : natural := 16   -- Bits in the integrating accumulator
161
    );
162
    port (
163
      -- System Clock and Clock Enable
164
      sys_rst_n   : in  std_logic;
165
      sys_clk     : in  std_logic;
166
      sys_clk_en  : in  std_logic;
167
 
168
      -- Settings
169
      input       : in  signed(INTEGRATOR_BITS-1 downto 0);
170
 
171
      -- Integration Result
172
      integrator  : out signed(INTEGRATOR_BITS-1 downto 0)
173
 
174
    );
175
  end leaky_integrator;
176
 
177
architecture beh of leaky_integrator is
178
 
179
  -- Constants
180
 
181
  -- Functions & associated types
182
 
183
  -- Signal Declarations
184
  signal sum     : signed(INTEGRATOR_BITS-1 downto 0);
185
  signal delta   : signed(INTEGRATOR_BITS-1 downto 0);
186
  signal m_term  : signed(INTEGRATOR_BITS+LEAK_FACTOR_BITS downto 0);
187
 
188
begin
189
 
190
-- The feedback term
191
m_term <= sum*to_signed(LEAK_FACTOR,LEAK_FACTOR_BITS+1);
192
 
193
-- The difference term
194
delta  <= input - m_term(m_term'length-1 downto m_term'length-delta'length);
195
 
196
-- The leaky integrator
197
process (sys_clk, sys_rst_n)
198
begin
199
  if (sys_rst_n='0') then
200
    sum <= to_signed(0,integrator'length);
201
  elsif (sys_clk'event and sys_clk='1') then -- rising edge
202
    if (sys_clk_en='1') then
203
      sum <= sum + delta;
204
    end if;
205
  end if;
206
end process;
207
 
208
-- The outputs
209
integrator <= sum;
210
 
211
end beh;
212
 
213
-------------------------------------------------------------------------------
214
-- Leaky Integrator with conditioned Digital Output
215
-------------------------------------------------------------------------------
216
--
217
-- Author: John Clayton
218
-- Date  : Oct. 11, 2013 Started Coding, drawing from various other sources.
219
--                       Created description.  Simulated it and saw that it
220
--                       works.
221
--         Sep. 20, 2017 Revised delta assignment, to eliminate custom
222
--                       resize function.
223
--                 
224
--
225
-- Description
226
-------------------------------------------------------------------------------
227
-- This module is a pretty simple digital "leaky integrator" designed to clean
228
-- up noisy repetitive signals by integrating them, and applying thresholds
229
-- to the integrated result.
230
--
231
--   The first order differential equation is of the form:
232
--
233
--     dx/dt = -leak_factor*x + input
234
--
235
-- The input is discretized in both time and amplitude.  A one bit digital
236
-- input can be mapped to the "input" signal by using a positive value for
237
-- '1' and a negative value for '0'
238
--
239
-- The "leak_factor" is a feedback term, so that "DC gain" is inversely
240
-- proportional to the leak_factor.
241
--
242
-- Due to the presence of the feedback term, the integration's DC value, or
243
-- constant term, gets "leaked" to zero over time.  This is nice because
244
-- the threshold centers around zero.
245
--
246
-- Hysteresis can be added so that the digital output transitions an amount
247
-- above or below zero, depending on the current value of the output.
248
--
249
-- Clear as mud?  Well, it's similar to a low-pass filter, and the hysteresis
250
-- also helps remove noise on the input signal.
251
--
252
-- The sys_rst_n input is an asynchronous reset.
253
 
254
library IEEE;
255
use IEEE.STD_LOGIC_1164.ALL;
256
use IEEE.NUMERIC_STD.ALL;
257
use IEEE.MATH_REAL.ALL;
258
 
259
  entity leaky_integrator_with_digital_output is
260
    generic(
261
      FACTOR_BITS     : natural := 10;  -- Make this less than INTEGRATOR_BITS
262
      HYSTERESIS_BITS : natural := 10;  -- Make this less than INTEGRATOR_BITS
263
      INTEGRATOR_BITS : natural := 16   -- Bits in the integrating accumulator
264
    );
265
    port (
266
      -- System Clock and Clock Enable
267
      sys_rst_n   : in  std_logic;
268
      sys_clk     : in  std_logic;
269
      sys_clk_en  : in  std_logic;
270
 
271
      -- Settings
272
      input       : in  signed(INTEGRATOR_BITS-1 downto 0);
273
      leak_factor : in  signed(FACTOR_BITS-1 downto 0);
274
      hysteresis  : in  unsigned(HYSTERESIS_BITS-1 downto 0);
275
 
276
      -- Integration Result
277
      integrator  : out signed(INTEGRATOR_BITS-1 downto 0);
278
 
279
      -- Conditioned Digital Output Signal
280
      output      : out std_logic
281
    );
282
  end leaky_integrator_with_digital_output;
283
 
284
architecture beh of leaky_integrator_with_digital_output is
285
 
286
  -- Constants
287
 
288
  -- Functions & associated types
289
 
290
  -- Signal Declarations
291
  signal sum     : signed(INTEGRATOR_BITS-1 downto 0);
292
  signal delta   : signed(INTEGRATOR_BITS-1 downto 0);
293
  signal m_term  : signed(INTEGRATOR_BITS+FACTOR_BITS-1 downto 0);
294
  signal out_l   : std_logic;
295
  signal hp_term : signed(INTEGRATOR_BITS-1 downto 0);
296
  signal hn_term : signed(INTEGRATOR_BITS-1 downto 0);
297
 
298
begin
299
 
300
-- The feedback term
301
m_term <= sum*leak_factor;
302
 
303
-- The difference term
304
delta  <= input - m_term(m_term'length-1 downto m_term'length-delta'length);
305
 
306
-- The leaky integrator
307
process (sys_clk, sys_rst_n)
308
begin
309
  if (sys_rst_n='0') then
310
    sum <= to_signed(0,integrator'length);
311
    out_l <= '0';
312
  elsif (sys_clk'event and sys_clk='1') then -- rising edge
313
    if (sys_clk_en='1') then
314
      sum <= sum + delta;
315
      if (out_l='0') then
316
        if (sum>hp_term) then
317
          out_l <= '1';
318
        end if;
319
      else
320
        if (sum<hn_term) then
321
          out_l <= '0';
322
        end if;
323
      end if;
324
    end if;
325
  end if;
326
end process;
327
 
328
-- The hysteresis terms
329
hp_term <= signed(resize(hysteresis,INTEGRATOR_BITS));
330
hn_term <= not(hp_term)+1;
331
 
332
-- The outputs
333
integrator <= sum;
334
output <= out_l;
335
 
336
end beh;
337
 
338
-------------------------------------------------------------------------------
339
-- Multi Stage Leaky Integrator with Digital Output
340
-------------------------------------------------------------------------------
341
--
342
-- Author: John Clayton
343
-- Date  : Oct. 11, 2013 Started Coding, drawing from various other sources.
344
--                       Created description.
345
--                 
346
--
347
-- Description
348
-------------------------------------------------------------------------------
349
-- This module implements N-stages of leaky integrators.  Each stage has the
350
-- same leak factor, which is a value fixed by generics.  Use powers of two
351
-- to avoid inferring multipliers.  The smallest value of 1 is actually a
352
-- pretty nice choice.  The LEAK_FACTOR_BITS generic determines how small
353
-- the leak factor is by setting the number of bits.  The integer is converted
354
-- as follows:
355
--
356
--   multiplicand = to_signed(LEAK_FACTOR,LEAK_FACTOR_BITS);
357
--
358
--   It seems that the smallest signed number is 2 bits wide - one for a sign
359
--   bit, and the other for magnitude.  So, LEAK_FACTOR_BITS must be >=2.
360
--   Between stages, an arithmetic shift right operation is inserted, which is
361
--   intended to automatically scale the signal to fit the next integrator.
362
--
363
-- The hysteresis value is only applied at the final stage output, to derive
364
-- the conditioned digital output signal.
365
--
366
-- The "leak_factor" is a feedback term, so that "DC gain" is inversely
367
-- proportional to the leak_factor.
368
--
369
-- Due to the presence of the feedback term, the integration's DC value, or
370
-- constant term, gets "leaked" to zero over time.  This is nice because
371
-- the threshold centers around zero.
372
--
373
-- Hysteresis can be added so that the digital output transitions an amount
374
-- above or below zero, depending on the current value of the output.
375
--
376
-- Clear as mud?  Well, it's similar to a low-pass filter, and the hysteresis
377
-- also helps remove noise on the input signal.
378
--
379
-- The more stages are used, the more low-pass filtering occurs.
380
--
381
-- The sys_rst_n input is an asynchronous reset.
382
 
383
library IEEE;
384
use IEEE.STD_LOGIC_1164.ALL;
385
use IEEE.NUMERIC_STD.ALL;
386
use IEEE.MATH_REAL.ALL;
387
 
388
library work;
389
use work.signal_conditioning_pack.all;
390
 
391
  entity multi_stage_leaky_integrator is
392
    generic(
393
      STAGES           : natural := 2;
394
      LEAK_FACTOR_BITS : natural := 5;  -- Inversely related to LP corner frequency. (Min=1)
395
      HYSTERESIS_BITS  : natural := 8;  -- Make this less than INTEGRATOR_BITS
396
      INTEGRATOR_BITS  : natural := 16  -- Bits in each integrating accumulator
397
    );
398
    port (
399
      -- System Clock and Clock Enable
400
      sys_rst_n   : in  std_logic;
401
      sys_clk     : in  std_logic;
402
      sys_clk_en  : in  std_logic;
403
 
404
      -- Settings
405
      input       : in  signed(INTEGRATOR_BITS-1 downto 0);
406
      hysteresis  : in  unsigned(HYSTERESIS_BITS-1 downto 0);
407
 
408
      -- Final Stage Integration Result
409
      integrator  : out signed(INTEGRATOR_BITS-1 downto 0);
410
 
411
      -- Conditioned Digital Output Signal
412
      output      : out std_logic
413
    );
414
  end multi_stage_leaky_integrator;
415
 
416
architecture beh of multi_stage_leaky_integrator is
417
 
418
  -- Constants
419
    -- This value has been found to preserve amplitude between stages,
420
    -- without appreciable growth or shrinkage of sum levels.
421
  constant STAGE_ASR   : natural := LEAK_FACTOR_BITS+1;
422
  constant LEAK_FACTOR : natural := 1;
423
 
424
  -- Functions & associated types
425
 
426
  -- Signal Declarations
427
  type sum_type is array (natural range STAGES-1 downto 0) of signed(INTEGRATOR_BITS-1 downto 0);
428
  signal sum_in  : sum_type;
429
  signal sum_out : sum_type;
430
  signal out_l   : std_logic;
431
  signal hp_term : signed(INTEGRATOR_BITS-1 downto 0);
432
  signal hn_term : signed(INTEGRATOR_BITS-1 downto 0);
433
 
434
begin
435
 
436
 
437
----------------------------------------------
438
leaky_gen : for nvar in 0 to STAGES-1 generate
439
begin
440
  lint : entity work.leaky_integrator(beh)
441
    generic map(
442
      LEAK_FACTOR_BITS => LEAK_FACTOR_BITS,
443
      LEAK_FACTOR      => LEAK_FACTOR,
444
      INTEGRATOR_BITS  => INTEGRATOR_BITS
445
    )
446
    port map(
447
      -- System Clock and Clock Enable
448
      sys_rst_n   => sys_rst_n,
449
      sys_clk     => sys_clk,
450
      sys_clk_en  => sys_clk_en,
451
 
452
      -- Settings
453
      input       => sum_in(nvar),
454
 
455
      -- Integration Result
456
      integrator  => sum_out(nvar)
457
 
458
    );
459
end generate;
460
 
461
sum_in(0) <= input;
462
sum_gen : for nvar in 1 to STAGES-1 generate
463
begin
464
  sum_in(nvar) <= shift_right(sum_out(nvar-1),STAGE_ASR);
465
end generate;
466
 
467
-- The hysteresis and digital output
468
process (sys_clk, sys_rst_n)
469
begin
470
  if (sys_rst_n='0') then
471
    out_l <= '0';
472
  elsif (sys_clk'event and sys_clk='1') then -- rising edge
473
    if (sys_clk_en='1') then
474
      if (out_l='0') then
475
        if (sum_out(STAGES-1)>hp_term) then
476
          out_l <= '1';
477
        end if;
478
      else
479
        if (sum_out(STAGES-1)<hn_term) then
480
          out_l <= '0';
481
        end if;
482
      end if;
483
    end if;
484
  end if;
485
end process;
486
 
487
-- The hysteresis terms
488
hp_term <= signed(resize(hysteresis,INTEGRATOR_BITS));
489
hn_term <= not(hp_term)+1;
490
 
491
-- The outputs
492
integrator <= sum_out(STAGES-1);
493
output <= out_l;
494
 
495
end beh;
496
 
497
-------------------------------------------------------------------------------
498
-- Integrating Pulse Stretcher
499
-------------------------------------------------------------------------------
500
--
501
-- Author: John Clayton
502
-- Date  : Oct. 24, 2013 Started Coding, drawing from various other sources.
503
--                       Created description.  Simulated it and saw that it
504
--                       works.
505
--                 
506
--
507
-- Description
508
-------------------------------------------------------------------------------
509
-- This module is a pretty simple digital pulse stretcher.  A high input pulse
510
-- present for more than MIN_CLKS clock cycles causes the INITIAL_OFFSET value
511
-- to be loaded into an accumulator.  The accumulator is then incremented by 
512
-- STRETCH_FACTOR each clock cycle that the input pulse remains high, and is
513
-- decremented by one for each clock cycle that the input pulse is low.
514
--
515
-- The output is driven high whenever the accumulator is positive.
516
--
517
-- The output pulse width is given by:
518
--
519
--   Tpulse_o = STRETCH_FACTOR*(Tpulse_i-MIN_CLKS) + INITIAL_OFFSET
520
--
521
-- The INITIAL_OFFSET can be used to overcome the effects of minimum input
522
-- pulse filtering.  Also, if a negative value is used for it, then the
523
-- output pulse is delayed by additional clock cycles beyond the MIN_CLKS
524
-- of delay already present.  Another use for the INITIAL_OFFSET value is
525
-- to "bridge together" a train of pulses which might have some jitter.
526
-- The INITIAL_OFFSET value allows for some slop of jitter to be covered
527
-- by the extra decay time, so that no "gaps" appear in the output pulse.
528
--
529
-- During the decay time, when the output is high, the arrival of a new pulse
530
-- will cause further charging of the accumulator.  There is no minimum pulse
531
-- width for this to occur.  The MIN_CLKS only applies to starting the unit
532
-- from a quiescent state.
533
--
534
-- The integrator is a signed quantity, so set INTEGRATOR_BITS accordingly,
535
-- because the integrator can only hold positive quantities up to
536
-- 2^(INTEGRATOR_BITS-1)-1.
537
--
538
-- The sys_rst_n input is an asynchronous reset.
539
 
540
library IEEE;
541
use IEEE.STD_LOGIC_1164.ALL;
542
use IEEE.NUMERIC_STD.ALL;
543
use IEEE.MATH_REAL.ALL;
544
 
545
library work;
546
use work.function_pack.all;
547
 
548
  entity integrating_pulse_stretcher is
549
    generic(
550
      MIN_CLKS        : natural :=  5; -- pulses below this many clocks are ignored
551
      RETRIGGERABLE   : natural :=  1; -- 1=restart on new pulses.  0=decay to zero before restarting
552
      STRETCH_FACTOR  : natural :=  2; -- 0=no output, 1=same size, 2=double
553
      INITIAL_OFFSET  : natural := 25; -- Value initially loaded into integrator
554
      INTEGRATOR_BITS : natural := 16  -- Bits in the integrating accumulator
555
    );
556
    port (
557
      -- System Clock and Clock Enable
558
      sys_rst_n   : in  std_logic;
559
      sys_clk     : in  std_logic;
560
      sys_clk_en  : in  std_logic;
561
 
562
      -- Input
563
      pulse_i     : in  std_logic;
564
 
565
      -- Output
566
      pulse_o     : out std_logic
567
 
568
    );
569
  end integrating_pulse_stretcher;
570
 
571
architecture beh of integrating_pulse_stretcher is
572
 
573
  -- Constants
574
  constant RUNT_BITS : natural := timer_width(MIN_CLKS);
575
 
576
  -- Functions & associated types
577
 
578
  -- Signal Declarations
579
  signal runt_count : unsigned(RUNT_BITS-1 downto 0);
580
  signal sum        : signed(INTEGRATOR_BITS-1 downto 0);
581
  signal pulse_i_r1 : std_logic;
582
  signal pulse_l    : std_logic;
583
 
584
begin
585
 
586
-- The integrator
587
process (sys_clk, sys_rst_n)
588
begin
589
  if (sys_rst_n='0') then
590
    runt_count <= to_unsigned(0,runt_count'length);
591
    sum        <= to_signed(0,sum'length);
592
    pulse_i_r1 <= '0';
593
  elsif (sys_clk'event and sys_clk='1') then -- rising edge
594
    if (sys_clk_en='1') then
595
      -- Detect rising edge of input pulse
596
      pulse_i_r1 <= pulse_i;
597
      -- When the pulse_i input is consecutively high, decrement the runt
598
      -- counter until it is zero.
599
      if (runt_count>0) then
600
        if (pulse_i='1') then
601
          runt_count <= runt_count-1;
602
        else
603
          runt_count <= to_unsigned(MIN_CLKS,runt_count'length);
604
        end if;
605
      end if;
606
      -- Trigger on rising edge of pulse_i
607
      if (pulse_i='1' and pulse_i_r1='0') then
608
        if (pulse_l='0' or (RETRIGGERABLE=1 and pulse_l='1')) then
609
          runt_count <= to_unsigned(MIN_CLKS,runt_count'length);
610
        end if;
611
      end if;
612
      -- Load initial offset into accumulator on final runt countdown
613
      if (runt_count=1) then
614
        sum <= to_signed(INITIAL_OFFSET,sum'length);
615
      end if;
616
      -- Either accumulate or decay, depending on input state
617
      if (pulse_i='1' and runt_count=0) then
618
        sum <= sum+STRETCH_FACTOR;
619
      elsif (pulse_i='0' and pulse_l='1') then
620
        sum <= sum-1;
621
      end if;
622
    end if;
623
  end if;
624
end process;
625
 
626
-- The output
627
pulse_l <= '1' when (sum>0) else '0';
628
pulse_o <= pulse_l;
629
 
630
end beh;
631
 

powered by: WebSVN 2.1.0

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