Hallo zusammen,
ich lerne seit ein paar Wochen intensiv VHDL und bin grad dran, ein DAC
über SPI mittels Spartan3 anzusteuern. Der DAC besitzt 2 Kanäle und die
Reihenfolge der zu übertragenden Daten sollte so sein (der DAC verlangt
16 Bits):
1. Übertragung: 0x9002 (Referenzspannung wählen)
2. Übertragung: 0x1XX0 (Wert Kanal A)
3. Übertragung: 0x8XX0 (Wert Kanal B)
Es sind also 3x je 16 Bits zu übertragen. Als SPI Master hab ich den von
Lothar Miller so ziemlich exakt übernommen (paar Änderungen musst ich
machen).
Hier mal der SPI Code:
1 | library IEEE;
|
2 | use IEEE.STD_LOGIC_1164.ALL;
|
3 | use IEEE.NUMERIC_STD.ALL;
|
4 |
|
5 | entity spi is
|
6 | Generic ( crystal_frequency : integer; -- in Hz
|
7 | spi_frequency : integer; -- in Hz
|
8 | data_length : integer -- Anzahl der zu übertragenden Bits
|
9 | );
|
10 | PORT ( TX_Data : in STD_LOGIC_VECTOR (data_length-1 downto 0); -- Sendedaten
|
11 | Data_out : out STD_LOGIC;
|
12 | CS : out STD_LOGIC;
|
13 | SCLK : out STD_LOGIC;
|
14 | TX_Start : in STD_LOGIC;
|
15 | TX_Done : out STD_LOGIC;
|
16 | clk : in STD_LOGIC
|
17 | );
|
18 | end spi;
|
19 |
|
20 | architecture Behavioral of spi is
|
21 | constant frequency_counter_upper_limit : integer := (crystal_frequency/(2*spi_frequency))-1;
|
22 | signal frequency_counter : integer range 0 to (crystal_frequency/(2*spi_frequency)) := frequency_counter_upper_limit;
|
23 |
|
24 | type states is (idle, active, finished); -- FSM Zustände
|
25 | signal spi_state : states := idle;
|
26 |
|
27 | signal spi_clk : STD_LOGIC;
|
28 | signal spi_clk_old : STD_LOGIC;
|
29 |
|
30 | signal bit_counter : integer range 0 to data_length; -- Counter, der die schon rausgeschobenen Bits zählt
|
31 |
|
32 | signal tx_reg : STD_LOGIC_VECTOR (data_length-1 downto 0) := (others=>'0');
|
33 | begin
|
34 | ------ FSM ------
|
35 | process (clk)
|
36 | begin -- SPI Mode 1: CLK Ruhe Pegel 1, Daten werden bei steigender Flanke ausgegeben und bei fallender eingelesen
|
37 | if clk'event and clk = '1' then
|
38 |
|
39 | if frequency_counter > 0 then -- Clock Enable für den SPI Takt erzeugen, doppelt so schneller Trigger, weil spi_clk jedes Mal nur invertiert wird
|
40 | frequency_counter <= frequency_counter - 1;
|
41 | else
|
42 | frequency_counter <= frequency_counter_upper_limit;
|
43 | end if;
|
44 |
|
45 | spi_clk_old <= spi_clk;
|
46 |
|
47 | case spi_state is
|
48 | when idle =>
|
49 | CS <= '1'; -- inaktiv
|
50 | TX_Done <= '0';
|
51 | bit_counter <= data_length;
|
52 | spi_clk <= '1';
|
53 | if TX_Start = '1' then
|
54 | spi_state <= active; -- Zustandsübergang
|
55 | CS <= '0';
|
56 | frequency_counter <= frequency_counter_upper_limit;
|
57 | end if;
|
58 |
|
59 | when active =>
|
60 | if frequency_counter = 0 then
|
61 | spi_clk <= not spi_clk;
|
62 | if bit_counter = 0 then -- alle Daten rausgeschoben
|
63 | spi_clk <= '1';
|
64 | spi_state <= finished; -- Zustandsübergang
|
65 | end if;
|
66 | if spi_clk = '0' then
|
67 | bit_counter <= bit_counter - 1;
|
68 | end if;
|
69 | end if;
|
70 |
|
71 | when finished =>
|
72 | CS <= '1'; -- inaktiv
|
73 | TX_Done <= '1';
|
74 | if TX_Start = '0' then -- warten bis Eingangsflag gelöscht wurde
|
75 | spi_state <= idle; -- Zustandsübergang
|
76 | end if;
|
77 | end case;
|
78 |
|
79 | end if;
|
80 | end process;
|
81 | ------ Sendeschieberegister ------
|
82 | process (clk)
|
83 | begin
|
84 | if clk'event and clk = '1' then
|
85 |
|
86 | if spi_state = idle then -- im IDLE Zustand die angelegten Daten übernehmen
|
87 | tx_reg <= TX_Data;
|
88 | end if;
|
89 | if spi_state = active and spi_clk = '1' and spi_clk_old = '0' then -- zur steigenden Flanke die Daten rausschieben
|
90 | tx_reg <= tx_reg(tx_reg'left-1 downto 0) & tx_reg(0); -- & Operator hängt STD_LOGIC_VECTOR und STD_LOGIC einfach hintereinander, linksschieben
|
91 | end if;
|
92 |
|
93 | end if;
|
94 | end process;
|
95 |
|
96 | SCLK <= spi_clk;
|
97 | Data_out <= tx_reg(tx_reg'left);
|
98 |
|
99 | end Behavioral;
|
Und der Code der FSM, die die 3 Übertragungen abarbeiten soll:
1 | library IEEE;
|
2 | use IEEE.STD_LOGIC_1164.ALL;
|
3 | use IEEE.NUMERIC_STD.ALL;
|
4 |
|
5 | entity threshold is
|
6 | Port ( ValueA : in STD_LOGIC_VECTOR (7 downto 0);
|
7 | ValueB : in STD_LOGIC_VECTOR (7 downto 0);
|
8 | WR : in STD_LOGIC;
|
9 | WR_Done : out STD_LOGIC := '0';
|
10 | Data_out : out STD_LOGIC;
|
11 | CS : out STD_LOGIC;
|
12 | SCLK : out STD_LOGIC;
|
13 | clk : in STD_LOGIC);
|
14 | end threshold;
|
15 |
|
16 | architecture Behavioral of threshold is
|
17 | -- Component SPI Deklaration
|
18 | component spi is
|
19 | Generic ( crystal_frequency : integer; -- in Hz
|
20 | spi_frequency : integer; -- in Hz
|
21 | data_length : integer -- Anzahl der zu übertragenden Bits
|
22 | );
|
23 | PORT ( TX_Data : in STD_LOGIC_VECTOR (data_length-1 downto 0); -- Sendedaten
|
24 | Data_out : out STD_LOGIC;
|
25 | CS : out STD_LOGIC;
|
26 | SCLK : out STD_LOGIC;
|
27 | TX_Start : in STD_LOGIC;
|
28 | TX_Done : out STD_LOGIC;
|
29 | clk : in STD_LOGIC
|
30 | );
|
31 | end component spi;
|
32 |
|
33 | signal TX_Data : STD_LOGIC_VECTOR (15 downto 0) := (others => '0');
|
34 | signal TX_Start : STD_LOGIC;
|
35 | signal TX_Done : STD_LOGIC;
|
36 |
|
37 | signal state : integer range 0 to 10 := 0;
|
38 | signal init_state : integer range 0 to 5 := 0;
|
39 |
|
40 | signal delay_counter : integer range 0 to 4095 := 4095;
|
41 |
|
42 | begin
|
43 | -- Component SPI Instanziierung
|
44 | spi_instance: component spi
|
45 | Generic MAP (crystal_frequency => 50000000, spi_frequency => 1000000, data_length => 16)
|
46 | PORT MAP ( TX_Data => TX_Data,
|
47 | Data_out => Data_out,
|
48 | CS => CS,
|
49 | SCLK => SCLK,
|
50 | TX_Start => TX_Start,
|
51 | TX_Done => TX_Done,
|
52 | clk => clk
|
53 | );
|
54 | -- FSM für die Initialisierung der Referenz-Spannung des DAC + 2 Bytes, die nacheinander über SPI rausgeschickt werden müssen
|
55 | process (clk)
|
56 | begin
|
57 | if clk'event and clk = '1' then
|
58 | case state is -- Initialisierungs-FSM
|
59 | when 0 =>
|
60 | case init_state is
|
61 | when 0 =>
|
62 | if delay_counter > 0 then
|
63 | delay_counter <= delay_counter - 1;
|
64 | else
|
65 | delay_counter <= 100;
|
66 | init_state <= 1;
|
67 | end if;
|
68 |
|
69 | when 1 =>
|
70 | if WR = '1' then
|
71 | TX_Data <= x"9002";
|
72 | init_state <= 2;
|
73 | end if;
|
74 |
|
75 | when 2 =>
|
76 | if delay_counter > 0 then
|
77 | delay_counter <= delay_counter - 1;
|
78 | else
|
79 | delay_counter <= 100;
|
80 | init_state <= 3;
|
81 | end if;
|
82 |
|
83 | when 3 =>
|
84 | TX_Start <= '1';
|
85 | init_state <= 4;
|
86 |
|
87 | when 4 =>
|
88 | if TX_Done = '1' then
|
89 | TX_Start <= '0';
|
90 | init_state <= 5;
|
91 | end if;
|
92 |
|
93 | when 5 =>
|
94 | if delay_counter > 0 then
|
95 | delay_counter <= delay_counter - 1;
|
96 | else
|
97 | delay_counter <= 100;
|
98 | init_state <= 0;
|
99 | state <= 1;
|
100 | end if;
|
101 |
|
102 | end case;
|
103 |
|
104 | when 1 =>
|
105 | -- if WR = '1' then
|
106 | -- TX_Data <= x"9002";
|
107 | TX_Data <= x"1" & ValueA & x"0";
|
108 | state <= 2;
|
109 | -- end if;
|
110 |
|
111 | when 2 =>
|
112 | if delay_counter > 0 then
|
113 | delay_counter <= delay_counter - 1;
|
114 | else
|
115 | delay_counter <= 100;
|
116 | state <= 3;
|
117 | end if;
|
118 |
|
119 | when 3 =>
|
120 | TX_Start <= '1';
|
121 | state <= 4;
|
122 |
|
123 | when 4 =>
|
124 | if TX_Done = '1' then
|
125 | TX_Start <= '0';
|
126 | state <= 5;
|
127 | end if;
|
128 |
|
129 | when 5 =>
|
130 | if delay_counter > 0 then
|
131 | delay_counter <= delay_counter - 1;
|
132 | else
|
133 | delay_counter <= 100;
|
134 | state <= 6;
|
135 | end if;
|
136 |
|
137 | when 6 =>
|
138 | TX_Data <= x"8" & ValueB & x"0"; -- 2. Byte mit ValueB
|
139 | state <= 7;
|
140 |
|
141 | when 7 =>
|
142 | if delay_counter > 0 then
|
143 | delay_counter <= delay_counter - 1;
|
144 | else
|
145 | delay_counter <= 100;
|
146 | state <= 8;
|
147 | end if;
|
148 |
|
149 | when 8 =>
|
150 | TX_Start <= '1';
|
151 | state <= 9;
|
152 |
|
153 | when 9 =>
|
154 | if TX_Done = '1' then
|
155 | TX_Start <= '0';
|
156 | state <= 10;
|
157 | end if;
|
158 |
|
159 | when 10 =>
|
160 | if delay_counter > 0 then
|
161 | delay_counter <= delay_counter - 1;
|
162 | else
|
163 | WR_Done <= '1';
|
164 | if WR = '0' then
|
165 | delay_counter <= 100;
|
166 | WR_Done <= '0';
|
167 | state <= 0;
|
168 | end if;
|
169 | end if;
|
170 |
|
171 | end case;
|
172 | end if;
|
173 | end process;
|
174 |
|
175 | end Behavioral;
|
Getriggert wird der Ablauf durch das WR-Signal. Die zu schickenden Werte
für den DAC sind ValueA und ValueB. Die ersten 16. Bit haben eine eigene
FSM, da ich diese mal als Initialiserung später ausgliedern will (muss
nicht jedes Mal geschickt werden, wenn getriggert wird).
Kommen wir nur zum eigentlichen Problem:
Wird nach dem Anschließen der Versorgungsspannung die FSM das erste Mal
getriggert, scheint der die Übertragung der ersten 16 Bits einfach zu
übergehen. Die Referenzspannung wird nicht eingestellt beim DAC. Man
kann auf dem DSO schön die Übertragung der anderen zwei 16 Bit Folgen
sehen, die erste Übertragung wird jedoch einfach nicht gesendet. Trigger
ich die FSM ein zweites oder drittes Mal, dann werden jeweils alle 3
Übertragungen durchgeführt und funktioniert auch.
Bei Bedarf kann ich auch mal Oszi Bilder von den Übertragungen anhängen.
Ich weiß einfach nicht mehr weiter. Ich hoffe, ihr könnt mir helfen.
Viele Grüße,
Benjamin