-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathADXL362Ctrl.vhd
760 lines (655 loc) · 35.7 KB
/
ADXL362Ctrl.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
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
-- Copied from the Digilent demo
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;
use IEEE.std_logic_signed.all;
use IEEE.math_real.all;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity ADXL362Ctrl is
generic
(
SYSCLK_FREQUENCY_HZ : integer := 100000000;
SCLK_FREQUENCY_HZ : integer := 1000000;
NUM_READS_AVG : integer := 16;
UPDATE_FREQUENCY_HZ : integer := 1000
);
port
(
SYSCLK : in STD_LOGIC; -- System Clock
RESET : in STD_LOGIC;
-- Accelerometer data signals
ACCEL_X : out STD_LOGIC_VECTOR (11 downto 0);
ACCEL_Y : out STD_LOGIC_VECTOR (11 downto 0);
--SPI Interface Signals
SCLK : out STD_LOGIC;
MOSI : out STD_LOGIC;
MISO : in STD_LOGIC;
SS : out STD_LOGIC
);
end ADXL362Ctrl;
architecture Behavioral of ADXL362Ctrl is
signal ACCEL_Z : STD_LOGIC_VECTOR (11 downto 0);
signal ACCEL_TMP : STD_LOGIC_VECTOR (11 downto 0);
signal Data_Ready : STD_LOGIC;
-- SPI Interface component declaration
component SPI_If is
generic
(
SYSCLK_FREQUENCY_HZ : integer:= 100000000;
SCLK_FREQUENCY_HZ : integer:= 1000000
);
port
(
SYSCLK : in STD_LOGIC; -- System Clock
RESET : in STD_LOGIC;
Din : in STD_LOGIC_VECTOR (7 downto 0); -- Data to be transmitted
Dout : out STD_LOGIC_VECTOR (7 downto 0); -- Data received;
Start : in STD_LOGIC; -- used to start the transmission
Done : out STD_LOGIC; -- Signaling that transmission ended
HOLD_SS : in STD_LOGIC; -- Signal that forces SS low in the case of multiple byte
-- transmit/receive mode
--SPI Interface Signals
SCLK : out STD_LOGIC;
MOSI : out STD_LOGIC;
MISO : in STD_LOGIC;
SS : out STD_LOGIC
);
end component;
--**************************************
-- Constant Definitions
--**************************************
-- To create the update frequency counter
constant UPDATE_DIV_RATE : integer := (SYSCLK_FREQUENCY_HZ / UPDATE_FREQUENCY_HZ);
constant SYS_CLK_PERIOD_PS : integer := ((1000000000 / SYSCLK_FREQUENCY_HZ) * 1000);
--ADXL 362 Read and Write Command
constant READ_CMD : STD_LOGIC_VECTOR (7 downto 0) := X"0B";
constant WRITE_CMD : STD_LOGIC_VECTOR (7 downto 0) := X"0A";
-- Data read will be always performed starting from Address X"0E",
-- representing XACC_H. A total number of 8 bytes will be read.
constant READ_STARTING_ADDR : STD_LOGIC_VECTOR (7 downto 0):= X"0E";
-- Status Register Read will be used to check when new data is available (Bit 0 is 1)
constant STATUS_REG_ADDR : STD_LOGIC_VECTOR (7 downto 0):= X"0B";
-- Number of bytes to write when configuring registers
constant NUMBYTES_CMD_CONFIG_REG : integer := 3;
-- Number of bytes to write when reading registers
constant NUMBYTES_CMD_READ : integer := 2;
-- Number of bytes to read when reading data from ADXL362
constant NUMBYTES_READ_DATA : integer := 8;
-- Number of bytes to read when reading status register from ADXL362
constant NUMBYTES_READ_STATUS : integer := 1;
-- number of command vectors to send, one command vector
-- represents ADXL362 register address followed by command byte,
-- i.e. one command vector will mean two bytes
constant NUM_COMMAND_VEC : integer := 4;
-- Number of reads to be performed for which average is calculated, default is 16
constant NUM_READS : natural := NUM_READS_AVG;
-- Number of extra bits when creating the average of the reads
constant NUM_READS_BITS : natural := natural(ceil(log(real(NUM_READS), 2.0)));
-- after each SPI transaction, SS needs to be inactive for at least 10ns before a new command is issued
constant SS_INACTIVE_PERIOD_NS : integer := 10000;
constant SS_INACTIVE_CLOCKS : integer := (SS_INACTIVE_PERIOD_NS/(SYS_CLK_PERIOD_PS/1000));
-- To specify encoding of the state machines
attribute FSM_ENCODING : string;
--SPI Interface Control Signals
signal Start : STD_LOGIC; -- Signal controlling the SPI interface, controlled by the SPI Send/Receive State Machine
signal Done : STD_LOGIC; -- Signaling that transmission ended, coming from the SPI interface
signal HOLD_SS : STD_LOGIC; -- Signal that forces SS low in the case of multiple byte
-- transmit/receive mode, controlled by the SPI Transaction State Machine
-- Create the initialization vector, i.e.
-- the register data to be written to initialize ADXL362
type rom_type is array (0 to ((2* NUM_COMMAND_VEC)-1)) of STD_LOGIC_VECTOR (7 downto 0);
constant Cmd_Reg_Data : rom_type := ( X"1F", X"52", -- Soft Reset Register Address and Reset Command
X"1F", X"00", -- Soft Reset Register Address, clear Command
X"2D", X"02", -- Power Control Register, Enable Measure Command
X"2C", X"14" -- Filter Control Register, 2g range, 1/4 Bandwidth, 200HZ Output Data Rate
);
--address the reg_data ROM
signal Cmd_Reg_Data_Addr: integer range 0 to (NUM_COMMAND_VEC - 1) := 0;
-- Enable Incrementing Cmd_Reg_Data_Addr, controlled by the ADXL Control State machine
signal EN_Advance_Cmd_Reg_Addr: STD_LOGIC := '0';
-- will enable incrementing by 2 Cmd_Reg_Data_Addr
signal Advance_Cmd_Reg_Addr: STD_LOGIC := '0';
-- signal that shows that all of the addresses were read
signal Cmd_Reg_Addr_Done : STD_LOGIC := '0';
-- SPI Transfer Send Data signals. Writing Commands will be always a 3-byte transfer,
-- therefore commands will be temporarry stored in a 3X8 shift register.
type command_reg_type is array (0 to 2) of STD_LOGIC_VECTOR (7 downto 0);
signal Cmd_Reg: command_reg_type := (X"00", X"00", WRITE_CMD);
-- command_reg control signals
signal Load_Cmd_Reg : STD_LOGIC := '0'; -- Controlled by the SPI Transaction State Machine,
-- the command register is load with the appropiate command
signal Shift_Cmd_Reg : STD_LOGIC := '0'; -- Controlled by the SPI Send/Receive State Machine,
-- advance to the next command when a byte was sent
-- to count the bytes to be sent
-- Cnt_Bytes_Sent will decrement at the same time when
-- cmd_reg is shifted, therefore its control signal is the same as
-- for Cmd_Reg: EN_Shift_Cmd_Reg
signal Cnt_Bytes_Sent : integer range 0 to 3 :=0;
-- Load Cnt_Bytes_Sent with the number of bytes to be sent
-- according to the command to be sent
signal Load_Cnt_Bytes_Sent : STD_LOGIC := '0'; -- controlled by the SPI Transaction State Machine
signal Reset_Cnt_Bytes : STD_LOGIC := '0'; -- Controlled by the Main State Machine
-- will reset both the sent and received byte counter
-- SPI Transfer Receive Data signals. Reading data will be a 8-byte transfer:
-- XACC_H, XACC_L, YACC_H, YACC_L, ZACC_H, ZACC_L, TEMP_H, TEMP_L
-- therefore an 8X8 shift register is created.
type data_reg_type is array (0 to (NUMBYTES_READ_DATA - 1)) of STD_LOGIC_VECTOR (7 downto 0);
signal Data_Reg: data_reg_type := (others => X"00");
-- data_reg control signals:
signal EN_Shift_Data_Reg : STD_LOGIC := '0'; -- Controlled by the SPI Send/Receive State Machine
-- Shift when a new byte was received
-- Data Reg will be shifted when a new byte comes, i.e. Shift_Data_Reg <= EN_Shift_Data_Reg AND Done;
signal Shift_Data_Reg : STD_LOGIC := '0';
-- to count the bytes to be received
-- Cnt_Bytes_Rec will decrement at the same time when Data_Reg is shifted,
-- therefore its control signal is the same as for Data_Reg: Shift_Data_Reg
signal Cnt_Bytes_Rec : integer range 0 to NUMBYTES_READ_DATA - 1 := 0;
-- Load Cnt_Bytes_Rec with the number of bytes to be received, controlled by the SPI Transaction State Machine
signal Load_Cnt_Bytes_Rec : STD_LOGIC := '0';
-- SPI Data to Send and Data Received registers
-- Data to send register will be loaded together with shifting
-- a new byte in Cmd_Reg, i.e. its control signal is Shift_Cmd_Reg
-- Data Received Register will be read when shifting Data_Reg
signal D_Send : STD_LOGIC_VECTOR (7 downto 0) := X"00";
signal D_Rec : STD_LOGIC_VECTOR (7 downto 0) := X"00";
-- SPI Send/Receive State Machine internal condition signals
signal StartSpiSendRec : STD_LOGIC := '0'; -- Start SPI transfer, controlled by the SPI Transaction State Machine
signal SPI_RnW : STD_LOGIC := '0'; -- Write 3 bytes or write 2 bytes followed by read 1 byte or 8 bytes
signal SPI_WR_Done : STD_LOGIC := '0'; -- Active when the write transfer is done, i.e. 2 or 3 bytes were written
signal SPI_RD_Done : STD_LOGIC := '0'; -- Active when the read transfer is done, i.e. 8 bytes were read
-- SPI Send/Receive State Machine status signals, used by the SPI Transaction State Machine
signal SPI_SendRec_Done : STD_LOGIC := '0';
-- Define Control Signals, Status signals and States for the SPI Send/Receive State Machine
-- From MSB: 6:Shift_Cmd_Reg, 5:EN_Shift_Data_Reg, 4:SPI_SendRec_Done, 3:Start, 2:STC(2), 1:STC(1), 0:STC(0)
-- bit 6543210
constant stSpiSendRecIdle : STD_LOGIC_VECTOR (6 downto 0) := "0000000"; -- Idle state, wait for StartSpiSendRec
constant stSpiPrepareCmd : STD_LOGIC_VECTOR (6 downto 0) := "1000001"; -- Load D_Send with the next byte and shift the command register
constant stSpiSendStartW : STD_LOGIC_VECTOR (6 downto 0) := "0001011"; -- Send the Start command to the SPI interface
constant stSpiWaitOnDoneW : STD_LOGIC_VECTOR (6 downto 0) := "0000111"; -- Wait until Done comes
constant stSpiSendStartR : STD_LOGIC_VECTOR (6 downto 0) := "0001110"; -- Send Start command again to the SPI interface if read was requested
constant stSpiWaitOnDoneR : STD_LOGIC_VECTOR (6 downto 0) := "0100100"; -- Wait until Done comes
constant stSpiSendRecDone : STD_LOGIC_VECTOR (6 downto 0) := "0010101"; -- Done state, return to Idle
--State Machine Signal Definitions
signal StC_Spi_SendRec, StN_Spi_SendRec : STD_LOGIC_VECTOR (6 downto 0) := stSpiSendRecIdle;
--Force User Encoding for the State Machine
attribute FSM_ENCODING of StC_Spi_SendRec: signal is "USER";
-- Self-blocking counter for SS_INACTIVE_CLOCKS periods while SS is inactive
signal Cnt_SS_Inactive : integer range 0 to (SS_INACTIVE_CLOCKS -1) := 0;
-- controlled by the SPI Transaction State Machine
signal Reset_Cnt_SS_Inactive : STD_LOGIC := '0';
-- Signaling that SS_INACTIVE_PERIOD passed
signal Cnt_SS_Inactive_done : STD_LOGIC := '0';
-- Signaling that SPI Transaction is done
signal SPI_Trans_Done : STD_LOGIC := '0';
-- SPI Transaction State Machine internal Condition Signals, controlled
-- by the ADXL 362 Control State Machine
signal StartSpiTr : STD_LOGIC := '0'; -- Start SPI transaction
-- Define Control Signals, Status signals and States for the SPI Transaction State Machine
-- From MSB: 9:Load_Cmd_Reg, 8:Load_Cnt_Bytes_Sent, 7:Load_Cnt_Bytes_Rec, 6:StartSpiSendRec,
-- 5:HOLD_SS, 4:Reset_Cnt_SS_Inactive, 3:SPI_Trans_Done, 2:STC(2), 1:STC(1), 0:STC(0)
-- bit 9876543210
constant stSpiTransIdle : STD_LOGIC_VECTOR (9 downto 0) := "0000000000"; -- Idle state, wait for StartSpiTr
constant stSpiPrepAndSendCmd : STD_LOGIC_VECTOR (9 downto 0) := "1111100001"; -- Load Cmd_Reg with the command string and activate StartSpiSendRec
constant stSpiWaitonDoneSR : STD_LOGIC_VECTOR (9 downto 0) := "0000110011"; -- Wait until SPI_SendRec_Done becomes active
constant stSpiWaitForSsInact : STD_LOGIC_VECTOR (9 downto 0) := "0000000010"; -- Wait for SS_INACTIVE_PERIOD
constant stSpiTransDone : STD_LOGIC_VECTOR (9 downto 0) := "0000001110"; -- Done state, return to Idle
--State Machine Signal Definitions
signal StC_Spi_Trans, StN_Spi_Trans : STD_LOGIC_VECTOR (9 downto 0) := stSpiTransIdle;
--Force User Encoding for the State Machine
attribute FSM_ENCODING of StC_Spi_Trans: signal is "USER";
-- Data from the ADXL 362 will be sampled at a period defined by UPDATE_DIV_RATE
-- Divider used to generate the Sample_Rate_Tick, used also for timing
signal Sample_Rate_Div : integer range 0 to (UPDATE_DIV_RATE - 1) := 0;
signal Reset_Sample_Rate_Div : STD_LOGIC := '0';
signal Sample_Rate_Tick : STD_LOGIC := '0';
-- A number of 16 reads will be performed from the ADXL 362,
-- and their average will be sent as data
signal Cnt_Num_Reads : integer range 0 to (NUM_READS - 1) := 0;
signal CE_Cnt_Num_Reads : STD_LOGIC := '0'; -- enable counting, controlled by the ADXL 362 Control State Machine
signal Reset_Cnt_Num_Reads : STD_LOGIC := '0';
--Signaling that a number of 16 reads were done
signal Cnt_Num_Reads_Done : STD_LOGIC := '0';
-- Summing of incoming data will be stored in these signals
-- These will be used as accumulators, on two's complement
signal ACCEL_X_SUM : STD_LOGIC_VECTOR ((11 + (NUM_READS_BITS)) downto 0) := (others => '0');
signal ACCEL_Y_SUM : STD_LOGIC_VECTOR ((11 + (NUM_READS_BITS)) downto 0) := (others => '0');
signal ACCEL_Z_SUM : STD_LOGIC_VECTOR ((11 + (NUM_READS_BITS)) downto 0) := (others => '0');
signal ACCEL_TMP_SUM : STD_LOGIC_VECTOR ((11 + (NUM_READS_BITS)) downto 0) := (others => '0');
-- Enables Summing the incomming data
signal Enable_Sum : STD_LOGIC := '0';
-- Pipe Data_Ready to have stable data at the output when activates
signal Data_Ready_1 : STD_LOGIC := '0';
-- ADXL 362 Control State Machine - The Main State Machine Internal Condition Signal
signal Adxl_Data_Ready : STD_LOGIC := '0'; -- showing that data is ready, read from the ADXL 362 Status Register
signal Adxl_Conf_Err : STD_LOGIC := '0'; -- showing that a configuration error ocurred, read from the ADXL 362 Status Register
-- Define Control Signals, Status signals and States for the ADXL 362 Control State Machine
-- From MSB: 11:Reset_Cnt_Bytes, 10:EN_Advance_Cmd_Reg_Addr, 9:StartSpiTr, 8:Reset_Cnt_Num_Reads,
-- 7:CE_Cnt_Num_Reads, 6:Reset_Sample_Rate_Div, 5:Enable_Sum, 4:Data_Ready_1, 3:STC(3), 2:STC(2), 1:STC(1), 0:STC(0)
-- 11
-- bit 109876543210
constant stAdxlCtrlIdle : STD_LOGIC_VECTOR (11 downto 0) := "100100000000"; -- Idle state, wait for 10 clock periods before start
constant stAdxlSendResetCmd : STD_LOGIC_VECTOR (11 downto 0) := "011001000001"; -- Send the Reset Command for ADXL
constant stAdxlWaitResetDone : STD_LOGIC_VECTOR (11 downto 0) := "010000000011"; -- Wait for some time until ADXL initializes.
-- The sample rate divider is used for timing
constant stAdxlConf_Remaining : STD_LOGIC_VECTOR (11 downto 0) := "011001000010"; -- Clear the Reset Register,
-- then configure the remaining registers
constant stAdxlWaitSampleRateTick : STD_LOGIC_VECTOR (11 downto 0) := "000100000110"; -- wait until the sample time passes
constant stAdxlRead_Status : STD_LOGIC_VECTOR (11 downto 0) := "011001000111"; -- Read the status register from ADXL 362
constant stAdxlRead_Data : STD_LOGIC_VECTOR (11 downto 0) := "011000000101"; -- Read the data from ADXL 362
constant stAdxlFormatandSum : STD_LOGIC_VECTOR (11 downto 0) := "000010101101"; -- Store and sum the received data
-- If 16 reads were done, go to the Done state
constant stAdxlRead_Done : STD_LOGIC_VECTOR (11 downto 0) := "000001011111"; -- Done state, return to stAdxlWaitSampleRateTick
--State Machine Signal Definitions
signal StC_Adxl_Ctrl, StN_Adxl_Ctrl : STD_LOGIC_VECTOR (11 downto 0) := stAdxlCtrlIdle;
--Force User Encoding for the State Machine
attribute FSM_ENCODING of StC_Adxl_Ctrl: signal is "USER";
begin
--Instantiate the SPI interface first
SPI_Interface: SPI_If
generic map
(
SYSCLK_FREQUENCY_HZ => SYSCLK_FREQUENCY_HZ,
SCLK_FREQUENCY_HZ => SCLK_FREQUENCY_HZ
)
port map
(
SYSCLK => SYSCLK,
RESET => RESET,
Din => D_Send,
Dout => D_Rec,
Start => Start,
Done => Done,
HOLD_SS => HOLD_SS,
--SPI Interface Signals
SCLK => SCLK,
MOSI => MOSI,
MISO => MISO,
SS => SS
);
-- Assign the control and status signals of the SPI Send/Receive State Machine
Shift_Cmd_Reg <= StC_Spi_SendRec(6); -- Shift Cmd_Reg when New data is loading into D_Send
EN_Shift_Data_Reg <= StC_Spi_SendRec(5); -- Enable shifting the data register from D_Rec, shifting is performed when a new byte comes, i.e Done becomes active
SPI_SendRec_Done <= StC_Spi_SendRec(4); -- Transfer of the number of bytes is done
Start <= StC_Spi_SendRec(3); -- Send the Start command to the SPI interface
--in the stSpiSendStartW (writing) or stSpiSendStartR (Reading) states
-- Load D_Send with the new data to be transmitted
Load_D_Send: process (SYSCLK, RESET, Cmd_Reg, Shift_Cmd_Reg)
begin
if SYSCLK'EVENT AND SYSCLK = '1' then
if RESET = '1' then
D_Send <= X"00";
elsif Shift_Cmd_Reg = '1' then
D_Send <= Cmd_Reg (2);
end if;
end if;
end process Load_D_Send;
-- Assign the control and status signals of the SPI Transaction State Machine
Load_Cmd_Reg <= StC_Spi_Trans(9); -- Load the Command Register when preparing the command to be sent to ADXL
Load_Cnt_Bytes_Sent <= StC_Spi_Trans(8); -- Also load the counter of bytes to be sent
Load_Cnt_Bytes_Rec <= StC_Spi_Trans(7); -- And, in the case of reception, the counter of bytes to be received
StartSpiSendRec <= StC_Spi_Trans(6); -- Also send the start command to the SPI Send/Receive State Machine
-- Note that the signals above are active at the same time, i.e identical. They will be optimized by the synthesizer
HOLD_SS <= StC_Spi_Trans(5); -- Each SPI send/receive will be multiple byte transfer, so activate HOLD_SS
Reset_Cnt_SS_Inactive <= StC_Spi_Trans(4); -- Keep the Cnt_SS_Inactive counter reset, until the transfer is done
-- in the next state the state machine will raise SS for a period of SS_INACTIVE_PERIOD_NS
SPI_Trans_Done <= StC_Spi_Trans(3); -- Signals that the SPI transfer is done
-- Assign the control and status signals of the ADXL 362 Control State Machine
Reset_Cnt_Bytes <= StC_Adxl_Ctrl(11); -- Reset the counters for bytes to send and receive. These counters are reset
-- at initializing, then reloaded at each new transaction
EN_Advance_Cmd_Reg_Addr <= StC_Adxl_Ctrl(10); -- Advance the address of the command vectors, to load a new command
StartSpiTr <= StC_Adxl_Ctrl(9); -- Send the Start command to the SPI Transaction State Machine
Reset_Cnt_Num_Reads <= StC_Adxl_Ctrl(8); -- Reset the counter, once at initialization time, then before starting data read,
-- i.e in the stAdxlRead_Status state
CE_Cnt_Num_Reads <= StC_Adxl_Ctrl(7); -- Increment Cnt_Num_Reads after a new set of data come i.e. in the stAdxlFormatandSum state
Reset_Sample_Rate_Div <= StC_Adxl_Ctrl(6); -- Reset the Sample_Rate_Div counter before entering in the sample period wait state
-- i.e. in the stAdxlConf_Remaining and the stAdxlRead_Done
Enable_Sum <= StC_Adxl_Ctrl(5); -- After new data set come, enable summing
Data_Ready_1 <= StC_Adxl_Ctrl(4); -- To signal external components that new data set is available, coming from 16 reads
-- Load and shift Cmd_Reg according to the active commands
Load_Shift_Cmd_Reg: process (SYSCLK, Cmd_Reg, Cmd_Reg_Data_Addr, StC_Adxl_Ctrl, Load_Cmd_Reg, Shift_Cmd_Reg)
begin
if SYSCLK'EVENT AND SYSCLK = '1' then
if Load_Cmd_Reg = '1' then -- Load with data
if (StC_Adxl_Ctrl = stAdxlSendResetCmd)
or (StC_Adxl_Ctrl = stAdxlConf_Remaining) then -- In this case load with command vectors
Cmd_Reg(2) <= WRITE_CMD;
Cmd_Reg(1) <= Cmd_Reg_Data (2 * Cmd_Reg_Data_Addr);
Cmd_Reg(0) <= Cmd_Reg_Data ((2 * Cmd_Reg_Data_Addr) + 1);
elsif (StC_Adxl_Ctrl = stAdxlRead_Status) then
Cmd_Reg(2) <= READ_CMD;
Cmd_Reg(1) <= STATUS_REG_ADDR;
Cmd_Reg(0) <= X"00";
elsif (StC_Adxl_Ctrl = stAdxlRead_Data) then -- In this case load with command vectors
Cmd_Reg(2) <= READ_CMD;
Cmd_Reg(1) <= READ_STARTING_ADDR;
Cmd_Reg(0) <= X"00";
end if;
elsif Shift_Cmd_Reg = '1' then -- shift to load D_send with the new command byte
Cmd_Reg(2) <= Cmd_Reg(1);
Cmd_Reg(1) <= Cmd_Reg(0);
Cmd_Reg(0) <= X"00";
end if;
end if;
end process Load_Shift_Cmd_Reg;
-- Create the address counter for the Cmd_Reg_Data command vectors
-- Increment by two the Cmd_Reg_Data_Addr after a SPI Register Write transaction is done
Advance_Cmd_Reg_Addr <= EN_Advance_Cmd_Reg_Addr AND SPI_Trans_Done;
Count_Addr: process (SYSCLK, RESET, Cmd_Reg_Data_Addr, StC_Adxl_Ctrl, Advance_Cmd_Reg_Addr)
begin
if SYSCLK'EVENT AND SYSCLK = '1' then
if RESET = '1' or StC_Adxl_Ctrl = stAdxlCtrlIdle then
Cmd_Reg_Data_Addr <= 0;
elsif Advance_Cmd_Reg_Addr = '1' then
if Cmd_Reg_Data_Addr = (NUM_COMMAND_VEC - 1) then -- Avoid to address Cmd_Reg_Data out of range
Cmd_Reg_Data_Addr <= 0;
else
Cmd_Reg_Data_Addr <= Cmd_Reg_Data_Addr + 1;
end if;
end if;
end if;
end process Count_Addr;
-- Signal when all of the addresses were read
Cmd_Reg_Addr_Done <= '1' when Cmd_Reg_Data_Addr = (NUM_COMMAND_VEC - 1) else '0';
-- Shift Data_Reg when a new byte comes
Shift_Data_Reg <= EN_Shift_Data_Reg AND Done;
-- Read incoming data
Read_Data: process (SYSCLK, Shift_Data_Reg, D_Rec, Data_Reg) -- When reading the status register, one byte is read, therefore
variable i: integer range 0 to 6 := 0; -- the status register data will be on Data_Reg(0)
begin -- When reading incoming data, exactly 8 reads are performed,
if SYSCLK'EVENT AND SYSCLK = '1' then -- therefore no initialization is required for Data_Reg
if Shift_Data_Reg = '1' then
for i in 0 to 6 loop
Data_Reg(i+1) <= Data_Reg(i);
end loop;
Data_Reg(0) <= D_Rec;
end if;
end if;
end process Read_Data;
-- Count the bytes to be send and to be received
Count_Bytes_Send: process (SYSCLK, Reset_Cnt_Bytes, Load_Cnt_Bytes_Sent, Shift_Cmd_Reg, Cnt_Bytes_Sent)
begin
if SYSCLK'EVENT AND SYSCLK = '1' then
if Reset_Cnt_Bytes = '1' then
Cnt_Bytes_Sent <= 0;
elsif Load_Cnt_Bytes_Sent = '1' then
if (StC_Adxl_Ctrl = stAdxlSendResetCmd)
or (StC_Adxl_Ctrl = stAdxlConf_Remaining) then -- In this case send 3 command bytes
-- Decrementing and shifting Cmd_Reg will be done BEFORE sending data
-- through the serial interface, therefore load NUMBYTES_CMD_CONFIG_REG or NUMBYTES_CMD_READ.
-- The condition to end SPI send operation is Cnt_Bytes_Sent = 0 AND Done = '1'
Cnt_Bytes_Sent <= NUMBYTES_CMD_CONFIG_REG;
elsif (StC_Adxl_Ctrl = stAdxlRead_Status)
or (StC_Adxl_Ctrl = stAdxlRead_Data) then -- In the case of read command, send 2 command bytes
Cnt_Bytes_Sent <= NUMBYTES_CMD_READ;
else
Cnt_Bytes_Sent <= 0;
end if;
elsif Shift_Cmd_Reg = '1' then -- When shifting Cmd_Reg, decrement the counter
if Cnt_Bytes_Sent = 0 then
Cnt_Bytes_Sent <= 0; -- Stay at 0, reload at the next SPI transaction
else
Cnt_Bytes_Sent <= Cnt_Bytes_Sent - 1;
end if;
end if;
end if;
end process Count_Bytes_Send;
Count_Bytes_Rec: process (SYSCLK, Reset_Cnt_Bytes, Load_Cnt_Bytes_Rec, Shift_Data_Reg, Cnt_Bytes_Rec)
begin
if SYSCLK'EVENT AND SYSCLK = '1' then
if Reset_Cnt_Bytes = '1' then
Cnt_Bytes_Rec <= 0;
elsif Load_Cnt_Bytes_Rec = '1' then
if (StC_Adxl_Ctrl = stAdxlRead_Status) then -- In this case we have to read 1 byte
-- Decrementing and shifting Data_Reg will be done AFTER sending data
-- through the serial interface, therefore load NUMBYTES_READ_STATUS - 1 or NUMBYTES_READ_DATA - 1.
-- The condition to end SPI receive operation is Cnt_Bytes_Rec = 0 AND Done = '1'
Cnt_Bytes_Rec <= NUMBYTES_READ_STATUS - 1;
elsif (StC_Adxl_Ctrl = stAdxlRead_Data) then -- In the case we have to read 8 bytes
Cnt_Bytes_Rec <= NUMBYTES_READ_DATA -1;
else
Cnt_Bytes_Rec <= 0;
end if;
elsif Shift_Data_Reg = '1' then -- When shifting Data_Reg, decrement the counter
if Cnt_Bytes_Rec = 0 then
Cnt_Bytes_Rec <= 0; -- Stay at 0, reload at the next SPI transaction
else
Cnt_Bytes_Rec <= Cnt_Bytes_Rec - 1;
end if;
end if;
end if;
end process Count_Bytes_Rec;
-- Create the Sample_Rate_Div counter and the Sample_Rate_Tick signal
Count_Sample_Rate_Div: process (SYSCLK, Reset_Sample_Rate_Div, Sample_Rate_Div)
begin
if SYSCLK'EVENT AND SYSCLK = '1' then
if Reset_Sample_Rate_Div = '1' then
Sample_Rate_Div <= 0;
elsif Sample_Rate_Div = (UPDATE_DIV_RATE - 1) then
Sample_Rate_Div <= 0;
else
Sample_Rate_Div <= Sample_Rate_Div + 1;
end if;
end if;
end process Count_Sample_Rate_Div;
Sample_Rate_Tick <= '1' when Sample_Rate_Div = (UPDATE_DIV_RATE - 1) else '0';
-- Create the Cnt_Num_Reads counter, self-blocking
Count_Num_Reads: process (SYSCLK, Reset_Cnt_Num_Reads, CE_Cnt_Num_Reads, Cnt_Num_Reads)
begin
if SYSCLK'EVENT AND SYSCLK = '1' then
if Reset_Cnt_Num_Reads = '1' then
Cnt_Num_Reads <= 0;
elsif CE_Cnt_Num_Reads = '1' then
if Cnt_Num_Reads = (NUM_READS - 1) then
Cnt_Num_Reads <= (NUM_READS - 1);
else
Cnt_Num_Reads <= Cnt_Num_Reads + 1;
end if;
end if;
end if;
end process Count_Num_Reads;
Cnt_Num_Reads_Done <= '1' when Cnt_Num_Reads = (NUM_READS - 1) else '0';
-- Create the Cnt_SS_Inactive counter, also self_blocking
Count_SS_Inactive: process (SYSCLK, RESET, Reset_Cnt_SS_Inactive, Cnt_SS_Inactive)
begin
if SYSCLK'EVENT AND SYSCLK = '1' then
if RESET = '1' or Reset_Cnt_SS_Inactive = '1' then
Cnt_SS_Inactive <= 0;
elsif Cnt_SS_Inactive = (SS_INACTIVE_CLOCKS - 1) then
Cnt_SS_Inactive <= (SS_INACTIVE_CLOCKS - 1);
else
Cnt_SS_Inactive <= Cnt_SS_Inactive + 1;
end if;
end if;
end process Count_SS_Inactive;
Cnt_SS_Inactive_done <= '1' when Cnt_SS_Inactive = (SS_INACTIVE_CLOCKS - 1) else '0';
-- SPI Send/Receive State Machine internal condition signals
-- SPI_RnW will be controlled according to the states of the Adxl 362 Control state machine
Set_SPI_RnW: process (SYSCLK, StC_Adxl_Ctrl)
begin
if SYSCLK'EVENT AND SYSCLK = '1' then
if (StC_Adxl_Ctrl = stAdxlRead_Status)
or (StC_Adxl_Ctrl = stAdxlRead_Data) then
SPI_RnW <= '1';
else
SPI_RnW <= '0';
end if;
end if;
end process Set_SPI_RnW;
-- SPI Send/Receive State machine internal condition signals
SPI_WR_Done <= '1' when Cnt_Bytes_Sent = 0 AND Done = '1' else '0';
SPI_RD_Done <= '1' when Cnt_Bytes_Rec = 0 AND Done = '1' else '0';
-- Spi Send/Receive State Machine register process
Register_StC_Spi_SendRec: process (SYSCLK, RESET, StN_Spi_SendRec)
begin
if SYSCLK'EVENT AND SYSCLK = '1' then
if RESET = '1' then
StC_Spi_SendRec <= stSpiSendRecIdle;
else
StC_Spi_SendRec <= StN_Spi_SendRec;
end if;
end if;
end process Register_StC_Spi_SendRec;
-- Spi Send/Receive State Machine transitions process
Cmb_StC_Spi_SendRec: process (StC_Spi_SendRec, StartSpiSendRec, StartSpiSendRec,
SPI_WR_Done, SPI_RD_Done, SPI_RnW, Done)
begin
StN_Spi_SendRec <= StC_Spi_SendRec; -- Default: Stay in the current state
case (StC_Spi_SendRec) is
when stSpiSendRecIdle => if (StartSpiSendRec = '1') then StN_Spi_SendRec <= stSpiPrepareCmd; end if;
when stSpiPrepareCmd => StN_Spi_SendRec <= stSpiSendStartW;
when stSpiSendStartW => StN_Spi_SendRec <= stSpiWaitOnDoneW;
when stSpiWaitOnDoneW => if (SPI_RnW = '1') then -- in the case of a read command proceed to reading data, if writing is done
if (SPI_WR_Done = '1') then StN_Spi_SendRec <= stSpiSendStartR;
elsif (Done = '1') then StN_Spi_SendRec <= stSpiPrepareCmd; -- Return to send the next command byte
end if;
else
if (SPI_WR_Done = '1') then StN_Spi_SendRec <= stSpiSendRecDone; -- Sending command bytes finished
elsif (Done = '1') then StN_Spi_SendRec <= stSpiPrepareCmd; -- Return to send the next command byte
end if;
end if;
when stSpiSendStartR => StN_Spi_SendRec <= stSpiWaitOnDoneR; --Send Start command to the SPI interface and wait until reads a byte
when stSpiWaitOnDoneR => if (SPI_RD_Done = '1') then StN_Spi_SendRec <= stSpiSendRecDone; -- If all of the bytes were read
elsif (Done = '1') then StN_Spi_SendRec <= stSpiSendStartR; -- Return and send another Start command to read
end if; -- the next byte
when stSpiSendRecDone => StN_Spi_SendRec <= stSpiSendRecIdle;
when others => StN_Spi_SendRec <= stSpiSendRecIdle;
end case;
end process Cmb_StC_Spi_SendRec;
-- SPI Transaction State Machine register process
Register_StC_Spi_Trans: process (SYSCLK, RESET, StN_Spi_Trans)
begin
if SYSCLK'EVENT AND SYSCLK = '1' then
if RESET = '1' then
StC_Spi_Trans <= stSpiTransIdle;
else
StC_Spi_Trans <= StN_Spi_Trans;
end if;
end if;
end process Register_StC_Spi_Trans;
-- SPI Transaction State Machine transitions process
Cmb_StC_Spi_Trans: process (StC_Spi_Trans, StartSpiTr, Cnt_SS_Inactive_done, SPI_SendRec_Done)
begin
StN_Spi_Trans <= StC_Spi_Trans; -- Default: Stay in the current state
case (StC_Spi_Trans) is
when stSpiTransIdle => if (StartSpiTr = '1') then StN_Spi_Trans <= stSpiPrepAndSendCmd; end if; -- Start SPI Transaction
when stSpiPrepAndSendCmd => StN_Spi_Trans <= stSpiWaitonDoneSR; -- Load Cmd_Reg, the Cnt_Bytes_Sent and Cnt_Bytes_Rec counters and send
-- the Start command to the Spi Send/Receive state machine
when stSpiWaitonDoneSR => if (SPI_SendRec_Done = '1') then StN_Spi_Trans <= stSpiWaitForSsInact; end if; -- SPI Send/Receive done,
-- Discativate SS for SS_INACTIVE_CLOCKS
when stSpiWaitForSsInact => if (Cnt_SS_Inactive_done = '1') then StN_Spi_Trans <= stSpiTransDone; end if; -- SS_INACTIVE_CLOCKS passed, go to
-- the Done state
when stSpiTransDone => StN_Spi_Trans <= stSpiTransIdle;
when others => StN_Spi_Trans <= stSpiTransIdle;
end case;
end process Cmb_StC_Spi_Trans;
-- The Status Register read will be on Data_Reg(0), bit 0 shows if new data is ready
-- Adxl_Data_Ready and Adxl_Conf_Err will be tested in the ADXL 362 Control State Machine, in the stAdxlRead_Status state
Adxl_Data_Ready <= Data_Reg(0)(0);
Adxl_Conf_Err <= Data_Reg(0)(7);
-- ADXL 362 Control State Machine register process
Register_StC_Adxl_Ctrl: process (SYSCLK, RESET, StN_Adxl_Ctrl)
begin
if SYSCLK'EVENT AND SYSCLK = '1' then
if RESET = '1' then
StC_Adxl_Ctrl <= stAdxlCtrlIdle;
else
StC_Adxl_Ctrl <= StN_Adxl_Ctrl;
end if;
end if;
end process Register_StC_Adxl_Ctrl;
-- ADXL 362 Control State Machine Transitions process
Cmb_StC_Adxl_Ctrl: process (StC_Adxl_Ctrl, Cnt_SS_Inactive_done, SPI_Trans_Done, Sample_Rate_Tick,
Cmd_Reg_Addr_Done, Adxl_Data_Ready, Adxl_Conf_Err, Cnt_Num_Reads_Done)
begin
StN_Adxl_Ctrl <= StC_Adxl_Ctrl; -- Default: Stay in the current state
case (StC_Adxl_Ctrl) is
when stAdxlCtrlIdle => if (Sample_Rate_Tick = '1') then StN_Adxl_Ctrl <= stAdxlSendResetCmd; end if; -- wait for some clock periods
-- before start
when stAdxlSendResetCmd => if (SPI_Trans_Done = '1') then StN_Adxl_Ctrl <= stAdxlWaitResetDone; end if; -- Send the Reset command to the ADXL 362
when stAdxlWaitResetDone => if (Sample_Rate_Tick = '1') then StN_Adxl_Ctrl <= stAdxlConf_Remaining; end if; -- wait for about 1mS for the
-- ADXL 362 to initialize
when stAdxlConf_Remaining => if ( Cmd_Reg_Addr_Done = '1' AND SPI_Trans_Done = '1') then -- all of the configuration register data were written
StN_Adxl_Ctrl <= stAdxlWaitSampleRateTick; -- into the ADXL 362
end if;
when stAdxlWaitSampleRateTick => if (Sample_Rate_Tick = '1') then StN_Adxl_Ctrl <= stAdxlRead_Status; end if; -- Read and check the
--status register
when stAdxlRead_Status => if SPI_Trans_Done = '1' then
if Adxl_Conf_Err = '1' then StN_Adxl_Ctrl <= stAdxlCtrlIdle; -- if error ocurred in configuration, go to the ilde state
-- and send reset command again
elsif Adxl_Data_Ready = '1' then StN_Adxl_Ctrl <= stAdxlRead_Data; -- If data is available, start data read
end if;
end if;
when stAdxlRead_Data => if (SPI_Trans_Done = '1') then StN_Adxl_Ctrl <= stAdxlFormatandSum; end if; -- If a set of data is read,
-- add it to the accumulators
when stAdxlFormatandSum => if (Cnt_Num_Reads_Done = '1') then
StN_Adxl_Ctrl <= stAdxlRead_Done; -- done 16 reads, go to the Done state
else
StN_Adxl_Ctrl <= stAdxlRead_Status; -- Proceed to the next read
end if;
when stAdxlRead_Done => StN_Adxl_Ctrl <= stAdxlWaitSampleRateTick; -- Wait for the next Sample_Rate_Tick, in an infinite loop
when others => StN_Adxl_Ctrl <= stAdxlCtrlIdle;
end case;
end process Cmb_StC_Adxl_Ctrl;
-- Create the accumulators
-- Data_Reg is shifted from 0 to 7, it means that after reading a set of data, Data_Reg will contain
-- Data_Reg(7) = XDATA_L,
-- Data_Reg(6) = XDATA_H,
-- Data_Reg(5) = YDATA_L,
-- Data_Reg(4) = YDATA_H,
-- Data_Reg(3) = ZDATA_L,
-- Data_Reg(2) = ZDATA_H,
-- Data_Reg(1) = TEMP_L,
-- Data_Reg(0) = TEMP_H
Sum_Data: process (SYSCLK, RESET, Data_Ready_1, Enable_Sum, Data_Reg,
ACCEL_X_SUM, ACCEL_Y_SUM, ACCEL_Z_SUM, ACCEL_TMP_SUM)
begin
if SYSCLK'EVENT AND SYSCLK = '1' then
if (RESET = '1' OR Data_Ready_1 = '1') then
ACCEL_X_SUM <= (others => '0');
ACCEL_Y_SUM <= (others => '0');
ACCEL_Z_SUM <= (others => '0');
ACCEL_TMP_SUM <= (others => '0');
elsif Enable_Sum = '1' then
ACCEL_X_SUM <= ACCEL_X_SUM + (Data_Reg(6)((3 + (NUM_READS_BITS)) downto 0) & Data_Reg(7));
ACCEL_Y_SUM <= ACCEL_Y_SUM + (Data_Reg(4)((3 + (NUM_READS_BITS)) downto 0) & Data_Reg(5));
ACCEL_Z_SUM <= ACCEL_Z_SUM + (Data_Reg(2)((3 + (NUM_READS_BITS)) downto 0) & Data_Reg(3));
ACCEL_TMP_SUM <= ACCEL_TMP_SUM + (Data_Reg(0)((3 + (NUM_READS_BITS)) downto 0) & Data_Reg(1));
end if;
end if;
end process Sum_Data;
-- Register the output data
Register_Output_Data: process (SYSCLK, RESET, Data_Ready_1, ACCEL_X_SUM,
ACCEL_Y_SUM, ACCEL_Z_SUM, ACCEL_TMP_SUM)
begin
if SYSCLK'EVENT AND SYSCLK = '1' then
if RESET = '1' then
ACCEL_X <= (others => '0');
ACCEL_Y <= (others => '0');
ACCEL_Z <= (others => '0');
ACCEL_TMP <= (others => '0');
elsif Data_Ready_1 = '1' then -- Divide by NUM_READS to create the average and set the output data
ACCEL_X <= ACCEL_X_SUM ((11 + (NUM_READS_BITS)) downto (NUM_READS_BITS)); -- 12 bits
ACCEL_Y <= ACCEL_Y_SUM ((11 + (NUM_READS_BITS)) downto (NUM_READS_BITS));
ACCEL_Z <= ACCEL_Z_SUM ((11 + (NUM_READS_BITS)) downto (NUM_READS_BITS));
ACCEL_TMP <= ACCEL_TMP_SUM ((11 + (NUM_READS_BITS)) downto (NUM_READS_BITS));
end if;
end if;
end process Register_Output_Data;
-- Pipe Data_Ready from Data_Ready_1
-- to have stable output data when Data_Ready becomes active
Pipe_Data_Ready: process (SYSCLK, RESET, Data_Ready_1)
begin
if SYSCLK'EVENT AND SYSCLK = '1' then
if RESET = '1' then
Data_Ready <= '0';
else
Data_Ready <= Data_Ready_1;
end if;
end if;
end process Pipe_Data_Ready;
end Behavioral;