Hallo! Ich bin FPGA-Neuling und befasse mich gerade mit dem FPGA-Board Nexys 4 von Digilent: http://www.digilentinc.com/Data/Products/NEXYS4/Nexys4_RM_VB2_Final_5.pdf Auf diesem Board ist der Temperatursensor ADT7420 verbaut: http://www.analog.com/static/imported-files/data_sheets/ADT7420.pdf Programmiert wird mit der ISE Design Suite 14.7. Mein späteres Ziel ist es, die Temperatur auf einer der 7-Segmentanzeigen in dezimal darzustellen. Leider weiß ich gerade nicht weiter, wie ich mit dem ADT7420 auf dem Board arbeiten kann. Wie ist es mir z.B. möglich, die Bausteinregister per VHDL so zu programmieren, dass der IC arbeitet wie ich es möchte und wie funktioniert das Auslesen der Temperaturregister? Der Umfang des Datenblattes erschlägt mich gerade etwas, so dass ich gar nicht weiß wo ich anfangen soll. Der Baustein ermöglicht auch ein direktes Auslesen der Temperaturregister beim Starten des ICs (S. 23 im Datenblatt ADT7420 bzw. S.22f Datenblatt FPGA-Board). Wenn es mir gelingen würde, die zwei 8-bit Register auszulesen und damit evtl. LEDs zum Leuchten zu bringen, wäre mir schon sehr geholfen. MfG Thelightener
Torch M. schrieb: > Wie ist es mir z.B. möglich, die Bausteinregister per VHDL so zu > programmieren, dass der IC arbeitet wie ich es möchte und wie > funktioniert das Auslesen der Temperaturregister? Das ist der zweite Schritt. > Auf diesem Board ist der Temperatursensor ADT7420 verbaut: Also musst du erst mal eine Komponente beschreiben, die das I2C Protokoll umsetzt und mit der du ein Byte über den I2C Bus versenden und empfangen kannst. Auf den Seiten 17 und 18 wird beschrieben wie das geht. Dann brauchst du einen Zustandsautomaten, der nacheinander über die vorher implementierte I3C Schnittstelle die richtigen Werte an den Sensor schickt und empfängt. Und von den (wenigen) 14 Registern, die der Baustein hat, sind für dich nur 5 interessant. Zuerst solltest du versuchen, das ID-Register auszulesen, denn dort muss der Wert 0xCB zurückkommen. > Der Baustein ermöglicht auch ein direktes Auslesen der > Temperaturregister beim Starten des ICs (S. 23 im Datenblatt ADT7420 Wo steht das genau?
Hallo, muss es wirklich direkt über VHDL sein? Bei solchen Dingen (Auslesen, Umwandeln in Dezimal, Anzeigen) kommt es nicht wirklich auf die Durchlaufzeit an und von daher denke ich, dass es wesentlich einfacher ist, wenn man es prozessorbasiert realisiert. Als Beispiel sei an dieser Stelle der Picoblaze vorgeschlagen. Einfach über zwei Ports mit dem Display und dem Temp-Sensor verbinden und die gesamte Ansteuerung und dazwischen das Umwandeln ins Dezimale per Software erledigen. Ich denke, das wird einfacher als die ganzen Module und Zustandsautomaten zu schreiben. Erst recht für einen FPGA-Neuling, wie Du selbst schreibst... Gruß, Thomas
Hallo, danke für eure Beiträge. Wie der I²C-Bus funktioniert habe ich (denke ich) überblickt und welche Bitfolgen ich erzeugen muss, damit der Baustein tut was er soll, weiß ich auch. Als nächstes möchte ich die Bits einer beliebige Bitfolge taktabhängig auf einen Ausgang geben, weiß aber noch nicht wie ich das bewerkstelligen kann. Wie kann ich z.B. die Bits von: signal bit_stream: std_logic_vector(3 downto 0) := "1010"; sequentiell auf einen Ausgang geben, angefangen beim MSB? @Lothar Miller Digilent Datenblatt S. 23, Abschnitt 12.3 @Thomas T. Da ich nun mal das genannte Board in der Hand halte, muss ich es damit auch realisieren.
Torch M. schrieb: > Wie kann ich z.B. die Bits von: > signal bit_stream: std_logic_vector(3 downto 0) := "1010"; > sequentiell auf einen Ausgang geben, angefangen beim MSB? Da sind zwei Ansätze denkbar: 1. ein Multiplexer 2. ein Schieberegister Für den 1. Ansatz brauchst du einen Zähler von 0..3, der dann als Index für den Zugriff auf die Bits verwendet wird. Für den 2. Weg brauchst du den '&' Operator (Concatenation). Für FPGAs empfehle ich die 2. Lösung, weil sie viele Flipflops haben, bei CPLDs ist die Nummer 1. wegen der mächtigen Produktterme besser. Hier ain paar Anwendungen für Schieberegister (einfach nach dem & suchen): http://www.lothar-miller.de/s9y/categories/42-RS232 http://www.lothar-miller.de/s9y/categories/55-PS2 http://www.lothar-miller.de/s9y/categories/50-RC-5
Torch M. schrieb: > Da ich nun mal das genannte Board in der Hand halte, muss ich es damit > auch realisieren. Davon bin ich auch ausgegangen... Gemeint war die Implementation einer kleinen CPU (Picoblaze) auf dem FPGA, welche dann über einen angeflanschten I2C-Bus den Sensor anspricht. Über die auf dieser CPU laufende Software wäre eine Fehlerdetektion auf dem I2C-Bus auch einfacher, als in reiner Hardware... Sicher ist eine reine VHDL-Lösung mittels Statemachines auch möglich. Wobei ich den Aufwand der "Binär->Dezimal"-Wandlung der Temperatur als nicht trivial einstufe (Das LSB hat eine Wertigkeit von 0.0625°C (oder 0.0078°C)). Gruß, Thomas
Thomas T. schrieb: > Wobei ich den Aufwand der "Binär-Dezimal"-Wandlung der Temperatur als > nicht trivial einstufe Das ist eine simple Multiplikation mit anschließendem Abschneiden der nicht relevanten Stellen...
Hallo, mit dem Code am Threadende versuche ich 7 Bits seriell auf einen Ausgang zu geben. Die Ausgabe klappt auch, allerdings nicht so wie erhofft. Im Anhang ist ein Screenshot des Simulationsergebnisses zu sehen. Man sieht, dass wenn enable auf '1' gesetzt wird, die FSM beim nächsten Takt nach shifting springt. Bei diesem Takt müsste allerdings (so habe ich es mir zumindest vorgestellt) sda schon das LSB von device_addr ausgeben (also 1), da die Wertigkeit von bitcnt 0 ist. Tu es aber nicht. Dieses Bit wird irgendwie abgeschnitten. Wo liegt das Problem?
1 | library IEEE; |
2 | use IEEE.STD_LOGIC_1164.ALL; |
3 | use IEEE.NUMERIC_STD.ALL; |
4 | -------------------------------------------------------------
|
5 | entity Proj_data_shift is |
6 | Port ( clk : in STD_LOGIC; |
7 | --rst : in STD_LOGIC;
|
8 | --scl : out STD_LOGIC;
|
9 | enable : in STD_LOGIC; |
10 | sda : inout STD_LOGIC); |
11 | end Proj_data_shift; |
12 | -------------------------------------------------------------
|
13 | architecture Behavioral of Proj_data_shift is |
14 | |
15 | constant device_addr: STD_LOGIC_VECTOR(6 downto 0) := "1110111"; |
16 | signal bitcnt: integer range 0 to 7; |
17 | |
18 | type data_shift is (idle, shifting); |
19 | signal state : data_shift := idle; |
20 | |
21 | begin
|
22 | -------------------------------------------------------------
|
23 | process begin |
24 | wait until rising_edge(clk); |
25 | case state is |
26 | |
27 | when idle => |
28 | SDA <= '0'; |
29 | if (enable = '1') then |
30 | state <= shifting; |
31 | end if; |
32 | |
33 | when shifting => |
34 | if (bitcnt < 7) then |
35 | bitcnt <= bitcnt + 1; |
36 | sda <= device_addr(bitcnt); |
37 | else
|
38 | bitcnt <= 0; |
39 | state <= idle; |
40 | end if; |
41 | end case; |
42 | end process; |
43 | -------------------------------------------------------------
|
44 | end behavioral; |
Torch M. schrieb: > Wo liegt das Problem? Dein Stichwort heißt: Latency. Eigentlich logisch: Wenn du zusammen mit dem Zustandswechsel etwas ausgeben oder ändern willst, dann musst du es zusammen mit dem Zustandswechsel aktualisieren.
1 | process begin |
2 | wait until rising_edge(clk); |
3 | case state is |
4 | |
5 | when idle => |
6 | SDA <= '0'; |
7 | if (enable = '1') then |
8 | state <= shifting; -- Zustandswechsel |
9 | sda <= device_addr(0); -- GLEICHZEITIG Signal ändern |
10 | bitcnt <= 1; -- Vorbereiten für den nächsten Takt |
11 | end if; |
12 | |
13 | when shifting => |
14 | if (bitcnt < 7) then |
15 | sda <= device_addr(bitcnt); |
16 | bitcnt <= bitcnt + 1; |
17 | else
|
18 | state <= idle; |
19 | end if; |
20 | end case; |
21 | end process; |
BTW: Auf einem FPGA wäre es effizienter, die Daten mit einem Schieberegister hinauszubefördern. Ein Multiplexer braucht viel Logik...
:
Bearbeitet durch Moderator
Hallo, ich habe mittlerweile den I²C-Bus zum Laufen gekriegt und kann den Sensor schreiben und lesen. Auch die Ausgabe auf der 7-Segment-Anzeige funktioniert. Leider ist mir ein Problem aufgefallen, dessen Ursprung ich einfach nicht finden kann. Wenn ich die Sensortemperatur (mittels Föhn) von Raumtemperatur bis meinetwegen 30°C hochjage und die Temperatur wieder abfällt, dann habe ich ab <26°C immer einen Sprung auf <=24°C. D.h. er überspringt in diesem Bereich einfach immer 2°C, so dass die angezeigte Temperatur letztendlich nicht stimmen kann. Einen Fehler bei der Umrechnung des Temperaturregister-Inhaltes und der Anzeige auf dem 7-Segment-Display schließe ich aus, da ich mir parallel dazu auch den Temperaturregister-Inhalt (16 Bit) auf den 16 LEDs anzeigen lasse. Eine Umrechnung der angezeigten Bits ergibt stets den angezeigten Wert auf der 7-Segment-Anzeige. Der Fehler muss also meiner Meinung nach in der FSM zur Beschreibung des I²C-Protokolls liegen. Leider bin ich auch nach langer Sucherei nach wie vor ratlos, wo das Problem liegen könnte. Mein I²C-Protokoll habe ich so ausgelegt, dass ich über zwei entsprechende Bits (rw bzw. tbr) festlegen kann, ob ein Register geschrieben oder gelesen werden (rw) soll und ob ein Byte oder zwei Byte gelesen werden sollen (tbr). Ich konfiguriere den Sensor auf 16-Bit Auflösung, gebe noch einige Schwellwerte für den Temperaturalarm vor und ende dann in einer Endlosschleife, in der nur noch die Temperaturregister mittels 2-Byte-read ausgelesen werden. Sobald die Bits gelesen worden sind, werden sie an das Modul zur Visualisierung weitergegeben. Die einzelnen Module habe ich per Schematic verbunden. Falls es jemanden gibt, der sich meinem Problem (was ich in der FSM im Status "two_byte_read" vermute) annehmen möchte: Der Code für mein I²C-Protokoll lautet wie folgt:
1 | library IEEE; |
2 | use IEEE.STD_LOGIC_1164.ALL; |
3 | use IEEE.NUMERIC_STD.ALL; |
4 | |
5 | entity I2C_Master_Controller is |
6 | Port ( |
7 | clock : in STD_LOGIC; |
8 | rst : in STD_LOGIC; -- reset |
9 | rw : in STD_LOGIC; -- read or write |
10 | tbr : in STD_LOGIC; -- two-byte-read |
11 | reg_addr_in : in STD_LOGIC_VECTOR(7 downto 0); --Registeradresse vom Konfigurationsmodul |
12 | data_in : in STD_LOGIC_VECTOR(7 downto 0); --Daten vom Konfigurationsmodul, die bei rw <= '0' in den Sensor geschrieben werden |
13 | busy : out STD_LOGIC; |
14 | data_out : out STD_LOGIC_VECTOR(15 downto 0);--Registerinhalt |
15 | scl : out STD_LOGIC; |
16 | sda : inout STD_LOGIC); |
17 | end I2C_Master_Controller; |
18 | |
19 | architecture Behavioral of I2C_Master_Controller is |
20 | |
21 | type state_type is (idle, start_condition, send_dev_addr, loop_send_dev_addr, get_ack, loop_get_ack, send_reg_addr, loop_send_reg_addr, repeat_condition,loop_repeat_condition, loop_again_repeat_condition, one_byte_read, loop_one_byte_read, get_no_ack, loop_get_no_ack, send_stop, loop_send_stop, loop_again_send_stop, write_data, loop_write_data, two_byte_read, loop_two_byte_read); |
22 | signal state, prev_state: state_type; |
23 | |
24 | constant dev_addr_w : std_logic_vector(7 downto 0) := "10010110";-- Sensoradresse mit Write-Bit |
25 | constant dev_addr_r : std_logic_vector(7 downto 0) := "10010111";--Sensoradresse mit Read-Bit |
26 | |
27 | signal tmp_data : STD_LOGIC_VECTOR(15 downto 0); |
28 | constant prescaler : integer := 100000000/400000; |
29 | signal data : std_logic_vector(7 downto 0); |
30 | signal bitcnt : integer range 0 to 7; |
31 | signal cnt_clk : integer range 0 to prescaler; |
32 | signal new_clk : STD_LOGIC; |
33 | signal sda_tmp : STD_LOGIC; |
34 | signal first_byte_sent : STD_LOGIC; --Bit für 2-Byte-Read: wird '1', sobald das erste Byte vom Sensor empfangen wurde. |
35 | |
36 | begin
|
37 | |
38 | sda <= 'Z' when sda_tmp = '1' else '0'; |
39 | -------------------------------------------------------------------------
|
40 | -------------------------------------------------------------------------
|
41 | process(new_clk, rst) |
42 | begin
|
43 | if (rst <= '0') then |
44 | scl <= '1'; |
45 | sda_tmp <= '1'; |
46 | tmp_data <= x"FFFF"; |
47 | data_out <= x"FFFF"; |
48 | first_byte_sent <= '1'; |
49 | data_out <= x"FFFF"; |
50 | bitcnt <= 7; |
51 | busy <= '0'; |
52 | state <= idle; |
53 | elsif rising_edge(new_clk) then |
54 | case state is |
55 | when idle => |
56 | busy <= '0'; |
57 | first_byte_sent <= '0'; |
58 | scl <= '1'; |
59 | sda_tmp <= '1'; |
60 | state <= start_condition; |
61 | -------------------------------------------------------------------------
|
62 | when start_condition => |
63 | busy <= '1'; |
64 | sda_tmp <= '0'; |
65 | bitcnt <= 7; |
66 | data <= dev_addr_w; |
67 | prev_state <= start_condition; |
68 | state <= send_dev_addr; |
69 | -------------------------------------------------------------------------
|
70 | when send_dev_addr => |
71 | scl <= '0'; |
72 | sda_tmp <= data(bitcnt); |
73 | state <= loop_send_dev_addr; |
74 | |
75 | when loop_send_dev_addr => |
76 | scl <= '1'; |
77 | if bitcnt /= 0 then |
78 | bitcnt <= bitcnt - 1; |
79 | state <= send_dev_addr; |
80 | else
|
81 | bitcnt <= 7; |
82 | case prev_state is |
83 | when start_condition => |
84 | prev_state <= send_dev_addr; |
85 | when repeat_condition => |
86 | prev_state <= repeat_condition; |
87 | when others => null; |
88 | end case; |
89 | state <= get_ack; |
90 | end if; |
91 | -------------------------------------------------------------------------
|
92 | when get_ack => |
93 | scl <= '0'; |
94 | sda_tmp <= '1'; |
95 | state <= loop_get_ack; |
96 | |
97 | when loop_get_ack => |
98 | scl <= '1'; |
99 | sda_tmp <= '0'; |
100 | case prev_state is |
101 | when send_dev_addr => |
102 | state <= send_reg_addr; |
103 | when send_reg_addr => |
104 | if rw = '0' then |
105 | bitcnt <= 7; |
106 | state <= write_data; |
107 | elsif rw <= '1' then |
108 | bitcnt <= 7; |
109 | state <= repeat_condition; |
110 | end if; |
111 | when repeat_condition => |
112 | if tbr <= '0' then |
113 | state <= one_byte_read; |
114 | elsif tbr <= '1' then |
115 | state <= two_byte_read; |
116 | end if; |
117 | when write_data => |
118 | state <= send_stop; |
119 | when two_byte_read => |
120 | first_byte_sent <= '1'; |
121 | state <= two_byte_read; |
122 | when others => |
123 | state <= idle; |
124 | end case; |
125 | -------------------------------------------------------------------------
|
126 | when send_reg_addr => |
127 | scl <= '0'; |
128 | sda_tmp <= reg_addr_in(bitcnt); |
129 | state <= loop_send_reg_addr; |
130 | |
131 | when loop_send_reg_addr => |
132 | scl <= '1'; |
133 | if bitcnt /= 0 then |
134 | bitcnt <= bitcnt - 1; |
135 | state <= send_reg_addr; |
136 | else
|
137 | bitcnt <= 7; |
138 | prev_state <= send_reg_addr; |
139 | state <= get_ack; |
140 | end if; |
141 | -------------------------------------------------------------------------
|
142 | when repeat_condition => |
143 | scl <= '0'; |
144 | sda_tmp <= '1'; |
145 | state <= loop_repeat_condition; |
146 | |
147 | when loop_repeat_condition => |
148 | scl <= '1'; |
149 | sda_tmp <= '1'; |
150 | state <= loop_again_repeat_condition; |
151 | |
152 | when loop_again_repeat_condition => |
153 | scl <= '1'; |
154 | sda_tmp <= '0'; |
155 | data <= dev_addr_r; |
156 | prev_state <= repeat_condition; |
157 | state <= send_dev_addr; |
158 | -------------------------------------------------------------------------
|
159 | when write_data => |
160 | scl <= '0'; |
161 | sda_tmp <= data_in(bitcnt); |
162 | state <= loop_write_data; |
163 | |
164 | when loop_write_data => |
165 | scl <= '1'; |
166 | if bitcnt /= 0 then |
167 | bitcnt <= bitcnt - 1; |
168 | state <= write_data; |
169 | else
|
170 | bitcnt <= 7; |
171 | prev_state <= write_data; |
172 | state <= get_ack; |
173 | end if; |
174 | -------------------------------------------------------------------------
|
175 | when one_byte_read => |
176 | scl <= '0'; |
177 | sda_tmp <= '1'; |
178 | state <= loop_one_byte_read; |
179 | |
180 | when loop_one_byte_read => |
181 | scl <= '1'; |
182 | data(bitcnt) <= sda; |
183 | if bitcnt /= 0 then |
184 | bitcnt <= bitcnt - 1; |
185 | state <= one_byte_read; |
186 | else
|
187 | bitcnt <= 7; |
188 | tmp_data(15 downto 8) <= data; |
189 | tmp_data(7 downto 0) <= (others => '0'); |
190 | state <= get_no_ack; |
191 | end if; |
192 | -------------------------------------------------------------------------
|
193 | when two_byte_read => |
194 | scl <= '0'; |
195 | sda_tmp <= '1'; |
196 | state <= loop_two_byte_read; |
197 | |
198 | when loop_two_byte_read => |
199 | scl <= '1'; |
200 | data(bitcnt) <= sda; |
201 | if bitcnt /= 0 then |
202 | bitcnt <= bitcnt - 1; |
203 | state <= two_byte_read; |
204 | elsif first_byte_sent <= '0' then |
205 | bitcnt <= 7; |
206 | tmp_data(15 downto 8) <= data; |
207 | state <= get_ack; |
208 | prev_state <= two_byte_read; |
209 | elsif first_byte_sent <= '1' then |
210 | bitcnt <= 7; |
211 | tmp_data(7 downto 0) <= data; |
212 | state <= get_no_ack; |
213 | end if; |
214 | -------------------------------------------------------------------------
|
215 | when get_no_ack => |
216 | scl <= '0'; |
217 | sda_tmp <= '1'; |
218 | data_out <= tmp_data; |
219 | state <= loop_get_no_ack; |
220 | |
221 | when loop_get_no_ack => |
222 | scl <= '1'; |
223 | state <= send_stop; |
224 | -------------------------------------------------------------------------
|
225 | when send_stop => |
226 | scl <= '0'; |
227 | sda_tmp <= '0'; |
228 | state <= loop_send_stop; |
229 | |
230 | when loop_send_stop => |
231 | scl <= '1'; |
232 | sda_tmp <= '0'; |
233 | state <= loop_again_send_stop; |
234 | |
235 | when loop_again_send_stop => |
236 | scl <= '1'; |
237 | sda_tmp <= '1'; |
238 | state <= idle; |
239 | -------------------------------------------------------------------------
|
240 | when others => |
241 | state <= idle; |
242 | -------------------------------------------------------------------------
|
243 | end case; |
244 | end if; |
245 | end process; |
246 | -------------------------------------------------------------------------
|
247 | -------------------------------------------------------------------------
|
248 | process (clock) |
249 | begin
|
250 | if rising_edge(clock) then |
251 | if (cnt_clk < prescaler) then |
252 | cnt_clk <= cnt_clk + 1; |
253 | if (cnt_clk < prescaler/2) then |
254 | new_clk <= '0'; |
255 | else
|
256 | new_clk <= '1'; |
257 | end if; |
258 | else
|
259 | cnt_clk <= 0; |
260 | end if; |
261 | end if; |
262 | |
263 | end process; |
264 | -------------------------------------------------------------------------
|
265 | -------------------------------------------------------------------------
|
266 | end Behavioral; |
Torch M. schrieb: > er überspringt in diesem Bereich einfach immer 2°C Nur von "oben nach unten" oder auch von "unten nach oben"? BTW: ich finde es interessant, ein einzelnes std_logic Bit auf "kleiner-gleich" zu vergleichen:
1 | ...
|
2 | elsif first_byte_sent <= '0' then |
3 | ...
|
4 | elsif first_byte_sent <= '1' then |
5 | ...
|
Hallo Lothar, er springt "in beide Richtungen". Das mit dem <= Vergleich ist natürlich ein Fehler, ist mir bislang noch nicht aufgefallen. Wundert mich, dass es deswegen keine Probleme gibt bei der Synthese.
Torch M. schrieb: > er springt "in beide Richtungen". Sind die Temperaturen an sich plausibel? Hast du bei den Timing-Constraints wenigstens den Takt angegeben? Passt dein erzeugtes Timing zu dem im Bild 2 vom Datenblatt?
Die Temperaturen sind plausibel und liegen immer so zwischen 21°C - 23°C, also bei Raumtemperatur. Mit "Timing-Constraints" habe ich mich noch gar nicht beschäftigt, weiß damit also noch nichts anzufangen. Das ändert sich aber jetzt. Geht es dir bei dem Timing-Constraint um den Takt, mit dem ich meine I²C-FSM betreibe? Wo kann ich mir mein erzeugtes Timing anschauen? Edit: Also ganz sicher bin ich mir doch nicht mehr ob die Temperaturen wirklich plausibel sind... er hat sich jetzt ca. bei 23°C eingependelt, bei mir ist es aber sicher ein paar Grad kälter.
:
Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.