-
Notifications
You must be signed in to change notification settings - Fork 0
/
ArmRS232Interface.vhd
446 lines (410 loc) · 21.6 KB
/
ArmRS232Interface.vhd
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
--------------------------------------------------------------------------------
-- UART einer EIA-232-Schnittstelle des HWPR-Prozessorsystems.
--------------------------------------------------------------------------------
-- Datum: ??.??.2013
-- Version: ?.?
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.ArmTypes.all;
use work.ArmConfiguration.all;
--------------------------------------------------------------------------------
-- Funktionsweise der Schnittstellenkomponente zum Datenbus:
-- Das Interface verfuegt ueber 4 sichbare Register:
-- Senderegister (RS232_TRM_REG)
-- Empfangsregister (RS232_RCV_REG)
-- Statusregister (RS232_STAT_REG)
-- Steuerregister (RS232_CTRL_REG)
--------------------------------------------------------------------------------
-- Das Ansprechen der Register erfolgt entweder Wort- oder Byteweise,
-- tatsaechlich wird aber immer nur das nur das niederwertigste Byte eines
-- Zugriffs beruecksichtigt.
-- In das Sendregegister sollte nur geschrieben werden, beim Lesen werden
-- Nullen ausgegeben. Empfangs- und Statusregister koennen nur gelesen
-- werden, Schreiboperationen sind wirkungslos.
-- Das Schreiben eines Datums vom Datenbus ins Senderegister wird als
-- Sendebefehl interpretiert, das Lesen eines Datums aus dem Empfangs-
-- register als Leseoperation.
--------------------------------------------------------------------------------
-- Interpretation des Statusregister:
-- Bit 0 zeigt an, dass ein neues Datum gelesen wurde und im Empfangs-
-- register liegt. Eine Leseoperation auf dem Empfangsregister setzt das
-- Bit zurueck. Bit 4 zeigt an, dass das Sendemodul mit der aktuellen
-- Uebertragung beschaeftigt ist, eine Schreiboperation auf das Sende-
-- register bleibt waehrenddessen wirkungslos. Ist das Bit = 0 und erfolgt
-- ein Schreibzugriff auf das Senderegister, wird das Bit im gleichen Takt
-- neu gesetzt.
--
-- Das Steuerregister hat vorlaeufig keine besondere Wirkung, kann aber
-- beschrieben werden.
--------------------------------------------------------------------------------
entity ArmRS232Interface is
port(
SYS_CLK : in std_logic;
SYS_RST : in std_logic;
-- Schnittstelle zum Datenbus
RS232_CS : in std_logic;
RS232_DnRW : in std_logic;
RS232_DMAS : IN std_logic_vector(1 downto 0);
RS232_DA : in std_logic_vector(3 downto 0);
RS232_DDIN : in std_logic_vector(31 downto 0);
RS232_DDOUT : out std_logic_vector(31 downto 0);
RS232_DABORT : out std_logic;
RS232_IRQ : out std_logic;
-- Serielle Empfangs- und Sendeleitungen
RS232_RXD : in std_logic;
RS232_TXD : out std_logic
);
end entity ArmRS232Interface;
architecture behave of ArmRS232Interface is
--------------------------------------------------------------------------------
-- Lokale Schnittstellensignale zum Datenbus zur Realisierung der
-- Tristate-Ausgaenge.
--------------------------------------------------------------------------------
signal DABORT_INTERNAL : std_logic;
signal DDOUT_INTERNAL : std_logic_vector(31 downto 0);
--------------------------------------------------------------------------------
-- Definition der lokalen, am Datenbus adressierbaren Register der
-- seriellen Schnittstelle. Sie werden Ausschliesslich im Block
-- INTERFACE_COMMUNICATION beschrieben!
--------------------------------------------------------------------------------
type RS232_REGISTER_SET_LOCAL_TYPE is array ( 0 to 2 ) of std_logic_vector(7 downto 0);
signal REGISTER_SET : RS232_REGISTER_SET_LOCAL_TYPE := (others => (others => '0'));
--------------------------------------------------------------------------------
-- Aliase fuer den Zugriff auf die 4 Register der RS232-Schnittstelle.
-- RS232_CTRL_REG ist aktuell funktionslos, liefert beim Lesen immer
-- 0 und Schreibzugriff haben keine Wirkung -> Beschreibung als Konstante.
--------------------------------------------------------------------------------
alias RS232_RCV_REG : std_logic_vector(7 downto 0) is REGISTER_SET(0);
alias RS232_TRM_REG : std_logic_vector(7 downto 0) is REGISTER_SET(1);
alias RS232_STAT_REG : std_logic_vector(7 downto 0) is REGISTER_SET(2);
constant RS232_CTRL_REG : std_logic_vector(7 downto 0) := (others => '0');
--------------------------------------------------------------------------------
-- Signale fuer die Kommunikation zwischen den 3 Bloecken im Modul.
--------------------------------------------------------------------------------
-- Signale vom RS232-Receiver zur Busschnittstelle INTERFACE_COMMUNICATION
signal DATA_RECEIVED : std_logic;
signal RECEIVER_DATA : std_logic_vector(7 downto 0);
--------------------------------------------------------------------------------
-- Steuer- und Statussignale zwischen RS232-Transmitter und
-- Busschnittstelle. Der Transmitter liest zusaetzlich Daten aus dem
-- lokalen Register RS232_TRM_REG.
--------------------------------------------------------------------------------
signal START_TRANSMISSION : std_logic;
signal TRANSMITTER_BUSY : std_logic;
--------------------------------------------------------------------------------
begin
--------------------------------------------------------------------------------
-- Kommunikationsschnittstelle, stellt die Verbindung zwischen Datenbus
-- und den RS232-Komponenten her.
--------------------------------------------------------------------------------
INTERFACE_COMMUNICATION : block is
begin
--------------------------------------------------------------------------------
-- Data Abort, wenn eine Wortzugriff mit nicht ausgerichteter Adresse
-- erfolgt oder ein Bytezugriff auf die nicht verwendeten hochwertigen
-- 24 Registerbits erfolgt.
--------------------------------------------------------------------------------
DABORT_INTERNAL <= '1' when ((RS232_DMAS /= DMAS_BYTE) and (RS232_DMAS /= DMAS_WORD)) or RS232_DA(1 downto 0) /= "00" else '0';
-- Daten- und Abortsignale werden nur getrieben, wenn das Modul tatsaechlich aktiv sein soll
RS232_DABORT <= DABORT_INTERNAL when RS232_CS = '1' else 'Z';
RS232_DDOUT <= DDOUT_INTERNAL when RS232_CS = '1' and RS232_DnRW = '0' else (others => 'Z');
--------------------------------------------------------------------------------
-- Interrupt ist bis auf weiteres direkt Bit 0 des Statusregistes, maskiert
-- wird ausschliesslich in Software durch das CPSR-IRQ-Maskenbit
--------------------------------------------------------------------------------
RS232_IRQ <= RS232_STAT_REG(0);
--------------------------------------------------------------------------------
-- Die vier Register der RS232-Schnittstelle liegen an 4 Adressen
-- hintereinander. Die Adressbits (3:2) waehlen das Register aus.
--------------------------------------------------------------------------------
GET_REGISTER : process(RS232_DA(3 downto 2), REGISTER_SET)
begin
case RS232_DA(3 downto 2) IS
when "00" =>
DDOUT_INTERNAL <= X"000000" & RS232_RCV_REG;
when "01" =>
DDOUT_INTERNAL <= (others => '0');
when "10" =>
DDOUT_INTERNAL <= X"000000" & RS232_STAT_REG;
when others =>
DDOUT_INTERNAL <= (others => '0');
end case;
end process GET_REGISTER;
--------------------------------------------------------------------------------
-- Schreibzugriffe vom Datenbus auf das Register RS232_TRM_REG setzen
-- dessen Inhalt und veranlassen das Senden des neuen Datums ueber die
-- TXD-Leitung.
--------------------------------------------------------------------------------
SET_REGISTER : process(SYS_CLK, REGISTER_SET, START_TRANSMISSION)
begin
REGISTER_SET <= REGISTER_SET;
START_TRANSMISSION <= START_TRANSMISSION;
if SYS_CLK'event and SYS_CLK = '1' then
if(SYS_RST = '1') then
REGISTER_SET <= (others => (others => '0'));
START_TRANSMISSION <= '0';
else
START_TRANSMISSION <= '0';
RS232_STAT_REG(7 downto 5) <= "000";
RS232_STAT_REG(3 downto 1) <= "000";
RS232_STAT_REG(4) <= TRANSMITTER_BUSY or START_TRANSMISSION;
-- Gueltiger Schreibzugriff auf das Transmissionsregister loest die Uebertragung aus
if(RS232_DnRW = '1' and RS232_CS = '1' and DABORT_INTERNAL = '0' and RS232_DA(3 downto 2) = "01" and START_TRANSMISSION = '0')then
if(TRANSMITTER_BUSY = '0')then
RS232_TRM_REG <= RS232_DDIN(7 downto 0);
START_TRANSMISSION <= '1';
RS232_STAT_REG(4) <= '1';
end if;
end if;
--------------------------------------------------------------------------------
-- Gueltiger Lesezugriff auf das Empfangsregister, setzt die Anzeige fuer
-- ein empfangenes Datum zurueck. Sollte im gleichen Takt erneut ein Datum
-- empfangen worden sein, bleibt das Bit gesetzt (naechster Abschnitt).
--------------------------------------------------------------------------------
if(RS232_DnRW = '0' and RS232_CS = '1' and DABORT_INTERNAL = '0' and RS232_DA(3 downto 2) = "00")then
RS232_STAT_REG(0) <= '0';
end if;
--------------------------------------------------------------------------------
-- Empfaenger zeigt an, dass ein neues Datum empfangen wurde, das
-- entsprechende Statusbit wird gesetzt.
--------------------------------------------------------------------------------
if(DATA_RECEIVED = '1')then
RS232_RCV_REG <= RECEIVER_DATA;
RS232_STAT_REG(0) <= '1';
end if;
end if;
end if;
end process SET_REGISTER;
end block INTERFACE_COMMUNICATION;
--------------------------------------------------------------------------------
-- Block, der das Verhalten eines RS232-Empfaengers beschreibt.
--------------------------------------------------------------------------------
RS232_RECEIVER : block is
--------------------------------------------------------------------------------
-- Exklusive Typen und Signale des Empfaengers. Alle Ausgangssignale, die
-- die Statemachine setzt, werden durch einen zusaetzlichen Prozess
-- registriert.
-- Die Statemachine liest ein von ihr direkt oder indirekt gesetztes Signal
-- ausschliesslich auf dem Umweg ueber das Register wieder ein, um
-- asynchrone Rueckkopplungen zu vermeiden.
--------------------------------------------------------------------------------
type RS232_RCV_STATE_TYPE is (RCV_IDLE, RCV_READ_BIT, RCV_STOPP);
signal RCV_STATE, RCV_NEXT_STATE : RS232_RCV_STATE_TYPE := RCV_IDLE;
constant DATA_REG_INIT_VALUE : std_logic_vector(7 downto 0) := "10000000";
signal RCV_DATA, RCV_DATA_REG : std_logic_vector(7 downto 0) := DATA_REG_INIT_VALUE;
-- Flipflop zum Aufsynchronisieren des Eingangssignals
signal DATA_IN_BIT_REG : std_logic := '1';
signal SET_DATA, SET_DATA_REG : std_logic;
signal DATA_RECEIVED_REG : std_logic := '1';
signal WSG_DELAY, WSG_DELAY_REG : std_logic_vector(31 downto 0);
signal WSG_START, WSG_START_REG : std_logic := '0';
-- WSG_WAIT wird von der Statemachine nur gelesen
signal WSG_WAIT : std_logic;
begin
WSG : entity work.ArmWaitStateGenAsync(BEHAVE)
generic map(
COUNT_VALUE_WIDTH => 32
)
port map(
SYS_CLK => SYS_CLK,
SYS_RST => SYS_RST,
WSG_COUNT_INIT => WSG_DELAY_REG,
WSG_START => WSG_START_REG,
WSG_WAIT => WSG_WAIT
);
-- Setzen des Zustandsregisters
SET_RCV_STATE_REG : process(SYS_CLK) is
begin
if SYS_CLK'event and SYS_CLK = '1' then
if SYS_RST = '1' then
RCV_STATE <= RCV_IDLE;
else
RCV_STATE <= RCV_NEXT_STATE;
end if;
end if;
end process SET_RCV_STATE_REG;
--------------------------------------------------------------------------------
-- Setzen der Synchronisationsregister, nur aus formalen Gruenden geschieht
-- dies nicht in einem Prozess mit dem Zustandsregister.
--------------------------------------------------------------------------------
SET_DATA_REGISTERS : process(SYS_CLK) is
begin
if SYS_CLK'event and SYS_CLK = '1' then
if SYS_RST = '1' then
DATA_IN_BIT_REG <= '1';
WSG_DELAY_REG <= std_logic_vector(RS232_START_DELAY);
RCV_DATA_REG <= (others => '0');
DATA_RECEIVED_REG <= '0';
WSG_START_REG <= '0';
SET_DATA_REG <= '0';
else
DATA_IN_BIT_REG <= RS232_RXD;
WSG_DELAY_REG <= WSG_DELAY;
RCV_DATA_REG <= RCV_DATA;
DATA_RECEIVED_REG <= '0';
WSG_START_REG <= WSG_START;
SET_DATA_REG <= SET_DATA;
if SET_DATA_REG = '1' then
RECEIVER_DATA <= RCV_DATA_REG(7 downto 0);
DATA_RECEIVED_REG <= '1';
end if;
end if;
end if;
end process SET_DATA_REGISTERS;
--------------------------------------------------------------------------------
-- DATA_RECEIVED zeigt der Kommunkationsschnittstelle an, dass ein neues
-- Datum empfangen wurde.
--------------------------------------------------------------------------------
DATA_RECEIVED <= DATA_RECEIVED_REG;
--------------------------------------------------------------------------------
-- Kern der FSM: Ermittlung des Nachfolgezustandes und Setzen der
-- Ausgangssignale, die dann in SET_DATA_REGISTERS in Register geschrieben
-- werden.
--------------------------------------------------------------------------------
SET_OUTPUTS_AND_NEXT_STATE : process(RCV_STATE,DATA_IN_BIT_REG,WSG_WAIT, RCV_DATA_REG) IS
begin
--------------------------------------------------------------------------------
-- Ausgangssignale die durch die FSM gesetzt und in jedem Zustand definiert
-- werden muessen:
-- RCV_NEXT_STATE
-- WSG_START
-- RCV_DATA
-- WSG_DELAY
-- SET_DATA
--------------------------------------------------------------------------------
-- Defaultwerte:
RCV_NEXT_STATE <= RCV_STATE;
WSG_START <= '0';
RCV_DATA <= RCV_DATA_REG;
WSG_DELAY <= std_logic_vector(RS232_DELAY);
SET_DATA <= '0';
case RCV_STATE is
when RCV_IDLE =>
if( DATA_IN_BIT_REG = '1' )then
RCV_NEXT_STATE <= RCV_IDLE;
WSG_START <= '0';
else
-- Beginn eines Startbits erkannt -> Beginn des Lesevorgangs
RCV_NEXT_STATE <= RCV_READ_BIT;
WSG_START <= '1';
end if;
RCV_DATA <= DATA_REG_INIT_VALUE;
--------------------------------------------------------------------------------
-- START_DELAY entspricht der 1,5-fachen Zeichendauer, sodass die
-- Empfangsleitung ca. in der Mitte des ersten Datenbits wieder abgetastet
-- wird.
--------------------------------------------------------------------------------
WSG_DELAY <= std_logic_vector(RS232_START_DELAY);
SET_DATA <= '0';
when RCV_READ_BIT =>
if( WSG_WAIT = '1' )then
RCV_NEXT_STATE <= RCV_READ_BIT;
WSG_START <= '0';
RCV_DATA <= RCV_DATA_REG;
else
RCV_DATA(7 downto 0) <= DATA_IN_BIT_REG & RCV_DATA_REG(7 downto 1);
WSG_START <= '1';
--------------------------------------------------------------------------------
-- RCV_DATA_REG wurde mit einer 1 im MSB initialisiert, die jetzt ganz
-- nach rechts geschoben wurde -> Schieberegister als Zaehler.
--------------------------------------------------------------------------------
if RCV_DATA_REG(0) = '1' then
RCV_NEXT_STATE <= RCV_STOPP;
else
RCV_NEXT_STATE <= RCV_READ_BIT;
end if;
end if;
WSG_DELAY <= std_logic_vector(RS232_DELAY);
SET_DATA <= '0';
when RCV_STOPP =>
RCV_DATA <= RCV_DATA_REG;
if( WSG_WAIT = '1' ) then
RCV_NEXT_STATE <= RCV_STOPP;
WSG_START <= '0';
SET_DATA <= '0';
RCV_DATA <= RCV_DATA_REG;
else
if(DATA_IN_BIT_REG = '1')then
RCV_NEXT_STATE <= RCV_IDLE;
WSG_START <= '0';
SET_DATA <= '1';
else
--------------------------------------------------------------------------------
-- 0 wird als Startsignal des naechsten Datensatzes interpretiert,
-- das aktuelle Datum aber nicht in der Kommunikationsschnittstelle
-- bekannt gemacht da ein korrektes Stoppbit fehlt.
--------------------------------------------------------------------------------
RCV_NEXT_STATE <= RCV_READ_BIT;
WSG_START <= '1';
SET_DATA <= '0';
end if;
end if;
WSG_DELAY <= std_logic_vector(RS232_DELAY);
when others =>
RCV_NEXT_STATE <= RCV_IDLE;
WSG_START <= '0';
RCV_DATA <= DATA_REG_INIT_VALUE;
WSG_DELAY <= std_logic_vector(RS232_START_DELAY);
SET_DATA <= '0';
end case;
end process SET_OUTPUTS_AND_NEXT_STATE;
end block RS232_RECEIVER;
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- Block, der einen RS232-Sender beschreibt und von Ihnen zu ergaenzen
-- ist. Veraendern Sie die Vorgaben ausserhalb des Blocks _nicht_.
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- RS232_TRM_REG ist 8 Bit gross
RS232_TRANSMITTER : block is
signal TRANSMIT_DATA : std_logic_vector(9 downto 0);
signal CLK_DELAY_COUNTER : unsigned (31 downto 0) := (others => '0');
signal TRANSMIT_COUNTER : integer := 0;
--Typ für die States selbst definiert (wie dummy werte)
type t_State is (BUSY, NOTBUSY);
signal State : t_State := NOTBUSY;
begin
--- Implementieren Sie den Sender als FSM ---------
FSM: process(SYS_CLK, State, START_TRANSMISSION) IS
begin
if (rising_edge(SYS_CLK)) then
if SYS_RST = '1' then
STATE <= NOTBUSY;
CLK_DELAY_COUNTER <= (others => '0');
TRANSMIT_COUNTER <= 0;
TRANSMITTER_BUSY <= '0';
end if;
case State is
when BUSY =>
-- durch DELAY (SLOW) kanns sein, dass gleiches Bit immer weider geschickt wird (gewollt)
RS232_TXD <= TRANSMIT_DATA(0);
CLK_DELAY_COUNTER <= CLK_DELAY_COUNTER + 1;
-- Schieberegister aktivieren, erst wenn Delay erreicht wurde
if (CLK_DELAY_COUNTER = RS232_DELAY) then
CLK_DELAY_COUNTER <= (others => '0');
-- Schieberegister -> counter erhöhen
TRANSMIT_DATA <= '1' & TRANSMIT_DATA(9 downto 1);
TRANSMIT_COUNTER <= TRANSMIT_COUNTER + 1;
end if;
-- finished transmission of RS232_TRM_REG :)
if (TRANSMIT_COUNTER = 10) then
STATE <= NOTBUSY;
TRANSMIT_COUNTER <= 0;
CLK_DELAY_COUNTER <= (others => '0');
end if; -- reset all again
when NOTBUSY =>
TRANSMITTER_BUSY <='0';
if(START_TRANSMISSION = '1') then
-- begin transmission
TRANSMITTER_BUSY <= '1';
State <= BUSY;
TRANSMIT_DATA <= '1' & RS232_TRM_REG & '0'; -- Copy with start '0' (LSB) and end bit '1' (MSB) concat
end if;
end case;
end if;
end process FSM;
end block RS232_TRANSMITTER;
end architecture behave;