~ruther/vhdl-spi-2

ref: 9ec022e5f06bb1d572c435809c0614e8e33fadde vhdl-spi-2/hdl_spi/src/spi_clkgen.vhd -rw-r--r-- 4.1 KiB
9ec022e5 — Rutherther fix: csn was rising too soon for divisors > 2 3 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.spi_pkg.all;

entity spi_clkgen is

  generic (
    DIVISORS         : natural_vector := (2, 4, 6, 8, 16, 32, 64, 128, 256);
    DIVISORS_LOG2    : natural := 3
  );

  port (
    clk_i              : in  std_logic;
    rst_in             : in  std_logic;
    start_i            : in  std_logic;
    -- next_data_i      : in  std_logic;
    div_sel_i          : in  std_logic_vector(DIVISORS_LOG2 - 1 downto 0);
    clock_polarity_i   : in  std_logic;
    clock_phase_i      : in  std_logic;
    sck_o              : out std_logic;
    sck_mask_i         : in  std_logic;
    counter_overflow_o : out std_logic;
    sample_data_o      : out std_logic;
    change_data_o      : out std_logic);

end entity spi_clkgen;

architecture a1 of spi_clkgen is
  constant MAX : natural := get_max_natural(DIVISORS);

  type state_t is (IDLE, CLK_GEN, SCK_GEN);

  signal running : std_logic;

  signal selected_divisor : natural range 0 to MAX := 1;
  signal changing : std_logic;

  signal curr_state : state_t;
  signal next_state : state_t;

  signal curr_counter : integer range 0 to MAX - 1;
  signal next_counter : integer range 0 to MAX - 1;

  signal curr_sck : std_logic;
  signal next_sck : std_logic;

begin  -- architecture a1

  set_data: process (clk_i) is
  begin  -- process set_data
    if rising_edge(clk_i) then          -- rising clock edge
      if rst_in = '0' then              -- synchronous reset (active low)
        curr_sck <= '0';
        curr_counter <= 0;
        curr_state <= IDLE;
      else
        curr_sck <= next_sck;
        curr_counter <= next_counter;
        curr_state <= next_state;
      end if;
    end if;
  end process set_data;

  state: process (all) is
  begin  -- process state
    next_state <= curr_state;
    running <= '0';

    sample_data_o <= '0';
    change_data_o <= '0';

    case curr_state is
      when IDLE =>
        if start_i = '1' then
          if sck_mask_i = '1' then
            next_state <= SCK_GEN;
            change_data_o <= not clock_phase_i;
          else
            next_state <= CLK_GEN;
          end if;
        end if;
      when CLK_GEN =>
        running <= '1';
        if start_i = '0' then
          next_state <= IDLE;
        elsif sck_mask_i = '1' then
          next_state <= SCK_GEN;
        end if;
      when SCK_GEN =>
        running <= '1';

        if changing = '1' then
          if curr_sck = clock_phase_i then
            sample_data_o <= sck_mask_i;
          else
            change_data_o <= sck_mask_i;
          end if;
        end if;

        if start_i = '0' and ((changing = '1' and curr_sck /= '0') or (curr_sck = '0')) then
          next_state <= IDLE;
          sample_data_o <= '0';
          change_data_o <= '0';
        elsif sck_mask_i =  '0' and ((changing = '1' and curr_sck /= '0') or (curr_sck = '0')) then
          next_state <= CLK_GEN;
          sample_data_o <= '0';
          change_data_o <= '0';
        end if;
      when others => null;
    end case;
  end process state;

  selected_divisor <= DIVISORS(to_integer(unsigned(div_sel_i)));

  changing <= '1' when curr_counter = 0 and running = '1' and curr_state = SCK_GEN else '0';

  next_counter <= selected_divisor - 2 when changing = '1' else
                  0 when curr_counter = 0 else
                  curr_counter - 1 when running = '1' else
                  selected_divisor - 1;

  -- sample_data_o <= '1' when curr_sck = clock_phase_i and changing = '1' else '0';
  -- change_data_o <= '1' when curr_sck /= clock_phase_i and changing = '1' else
  --                  '1' when clock_phase_i = '0' and start_i = '1' and running = '0' else
  --                  -- '1' when next_data_i = '1' else
  --                  '0';

  next_sck <= '0' when curr_state /= SCK_GEN else
              not curr_sck when changing = '1'
              else curr_sck when running = '1' else
              '0';

  sck_o <= clock_polarity_i when curr_state /= SCK_GEN else
           curr_sck when clock_polarity_i = '0' else
           not curr_sck;

  counter_overflow_o <= '1' when running = '1' and curr_counter = 0 else '0';

end architecture a1;
Do not follow this link