Statistics
| Branch: | Tag: | Revision:

amiro-lld / source / DW1000 / v1 / alld_dw1000_v1.c @ 119ec0d2

History | View | Annotate | Download (150.897 KB)

1 69a601a5 Cung Sang
/*
2
AMiRo-LLD is a compilation of low-level hardware drivers for the Autonomous Mini Robot (AMiRo) platform.
3
Copyright (C) 2016..2018  Thomas Schöpping et al.
4

5
This program is free software: you can redistribute it and/or modify
6
it under the terms of the GNU Lesser General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9

10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU Lesser General Public License for more details.
14

15
You should have received a copy of the GNU Lesser General Public License
16
along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
/*! ------------------------------------------------------------------------------------------------------------------
20
 * @file    deca_device.c
21
 * @brief   Decawave device configuration and control functions
22
 *
23
 * @attention
24
 *
25
 * Copyright 2013 (c) Decawave Ltd, Dublin, Ireland.
26
 *
27
 * All rights reserved.
28
 *
29
 */
30
31
#include <alld_DW1000.h>
32
#if (defined(AMIROLLD_CFG_DW1000) && (AMIROLLD_CFG_DW1000 == 1)) || defined(__DOXYGEN__)
33
34 33f54213 Cung Sang
#include <v1/alld_dw1000_regs_v1.h>
35 69a601a5 Cung Sang
#include <aos_thread.h>
36
#include <assert.h>
37
#include <string.h>
38
#include <stdlib.h>
39
#include <math.h>
40
41
42 33f54213 Cung Sang
// HW dependent implementation (see bottom of file)
43
static int writetospi(uint16_t headerLength,
44
               const        uint8_t *headerBuffer,
45
               uint32_t bodyLength,
46
               const        uint8_t *bodyBuffer);
47
48
static int readfromspi(uint16_t headerLength,
49
                const uint8_t *headerBuffer,
50
                uint32_t readlength,
51
                uint8_t *readBuffer);
52
53
54 69a601a5 Cung Sang
// Defines for enable_clocks function
55
#define FORCE_SYS_XTI  0
56
#define ENABLE_ALL_SEQ 1
57
#define FORCE_SYS_PLL  2
58
#define READ_ACC_ON    7
59
#define READ_ACC_OFF   8
60
#define FORCE_OTP_ON   11
61
#define FORCE_OTP_OFF  12
62
#define FORCE_TX_PLL   13
63
#define FORCE_LDE      14
64
65
// Defines for ACK request bitmask in DATA and MAC COMMAND frame control (first byte) - Used to detect AAT bit wrongly set.
66
#define FCTRL_ACK_REQ_MASK 0x20
67
// Frame control maximum length in bytes.
68
#define FCTRL_LEN_MAX 2
69
70
71
typedef struct {
72
    uint32_t lo32;
73
    uint16_t target[NUM_PRF];
74
} agc_cfg_struct ;
75
76
extern const agc_cfg_struct agc_config ;
77
78
//SFD threshold settings for 110k, 850k, 6.8Mb standard and non-standard
79
extern const uint16_t sftsh[NUM_BR][NUM_SFD];
80
81
extern const uint16_t dtune1[NUM_PRF];
82
83
#define XMLPARAMS_VERSION   (1.17f)
84
85
extern const uint32_t fs_pll_cfg[NUM_CH];
86
extern const uint8_t fs_pll_tune[NUM_CH];
87
extern const uint8_t rx_config[NUM_BW];
88
extern const uint32_t tx_config[NUM_CH];
89
extern const uint8_t dwnsSFDlen[NUM_BR]; //length of SFD for each of the bitrates
90
extern const uint32_t digital_bb_config[NUM_PRF][NUM_PACS];
91
//extern const uint8_t chan_idx[NUM_CH_SUPPORTED]; // move to header file
92
extern const double txpwr_compensation[NUM_CH];
93
94
#define PEAK_MULTPLIER  (0x60) //3 -> (0x3 * 32) & 0x00E0
95
#define N_STD_FACTOR    (13)
96
#define LDE_PARAM1      (PEAK_MULTPLIER | N_STD_FACTOR)
97
98
#define LDE_PARAM3_16 (0x1607)
99
#define LDE_PARAM3_64 (0x0607)
100
101
#define MIXER_GAIN_STEP (0.5)
102
#define DA_ATTN_STEP    (2.5)
103
104
// #define DWT_API_ERROR_CHECK     // define so API checks config input parameters
105
106
//-----------------------------------------
107
// map the channel number to the index in the configuration arrays below
108
// 0th element is chan 1, 1st is chan 2, 2nd is chan 3, 3rd is chan 4, 4th is chan 5, 5th is chan 7
109
const uint8_t chan_idx[NUM_CH_SUPPORTED] = {0, 0, 1, 2, 3, 4, 0, 5};
110
111
//-----------------------------------------
112
const uint32_t tx_config[NUM_CH] =
113
{
114
    RF_TXCTRL_CH1,
115
    RF_TXCTRL_CH2,
116
    RF_TXCTRL_CH3,
117
    RF_TXCTRL_CH4,
118
    RF_TXCTRL_CH5,
119
    RF_TXCTRL_CH7,
120
};
121
122
//Frequency Synthesiser - PLL configuration
123
const uint32_t fs_pll_cfg[NUM_CH] =
124
{
125
    FS_PLLCFG_CH1,
126
    FS_PLLCFG_CH2,
127
    FS_PLLCFG_CH3,
128
    FS_PLLCFG_CH4,
129
    FS_PLLCFG_CH5,
130
    FS_PLLCFG_CH7
131
};
132
133
//Frequency Synthesiser - PLL tuning
134
const uint8_t fs_pll_tune[NUM_CH] =
135
{
136
    FS_PLLTUNE_CH1,
137
    FS_PLLTUNE_CH2,
138
    FS_PLLTUNE_CH3,
139
    FS_PLLTUNE_CH4,
140
    FS_PLLTUNE_CH5,
141
    FS_PLLTUNE_CH7
142
};
143
144
//bandwidth configuration
145
const uint8_t rx_config[NUM_BW] =
146
{
147
    RF_RXCTRLH_NBW,
148
    RF_RXCTRLH_WBW
149
};
150
151
152
const agc_cfg_struct agc_config =
153
{
154
    AGC_TUNE2_VAL,
155
    { AGC_TUNE1_16M , AGC_TUNE1_64M }  //adc target
156
};
157
158
//DW non-standard SFD length for 110k, 850k and 6.81M
159
const uint8_t dwnsSFDlen[NUM_BR] =
160
{
161
    DW_NS_SFD_LEN_110K,
162
    DW_NS_SFD_LEN_850K,
163
    DW_NS_SFD_LEN_6M8
164
};
165
166
// SFD Threshold
167
const uint16_t sftsh[NUM_BR][NUM_SFD] =
168
{
169
    {
170
        DRX_TUNE0b_110K_STD,
171
        DRX_TUNE0b_110K_NSTD
172
    },
173
    {
174
        DRX_TUNE0b_850K_STD,
175
        DRX_TUNE0b_850K_NSTD
176
    },
177
    {
178
        DRX_TUNE0b_6M8_STD,
179
        DRX_TUNE0b_6M8_NSTD
180
    }
181
};
182
183
const uint16_t dtune1[NUM_PRF] =
184
{
185
    DRX_TUNE1a_PRF16,
186
    DRX_TUNE1a_PRF64
187
};
188
189
const uint32_t digital_bb_config[NUM_PRF][NUM_PACS] =
190
{
191
    {
192
        DRX_TUNE2_PRF16_PAC8,
193
        DRX_TUNE2_PRF16_PAC16,
194
        DRX_TUNE2_PRF16_PAC32,
195
        DRX_TUNE2_PRF16_PAC64
196
    },
197
    {
198
        DRX_TUNE2_PRF64_PAC8,
199
        DRX_TUNE2_PRF64_PAC16,
200
        DRX_TUNE2_PRF64_PAC32,
201
        DRX_TUNE2_PRF64_PAC64
202
    }
203
};
204
205
const uint16_t lde_replicaCoeff[PCODES] =
206
{
207
    0, // No preamble code 0
208
    LDE_REPC_PCODE_1,
209
    LDE_REPC_PCODE_2,
210
    LDE_REPC_PCODE_3,
211
    LDE_REPC_PCODE_4,
212
    LDE_REPC_PCODE_5,
213
    LDE_REPC_PCODE_6,
214
    LDE_REPC_PCODE_7,
215
    LDE_REPC_PCODE_8,
216
    LDE_REPC_PCODE_9,
217
    LDE_REPC_PCODE_10,
218
    LDE_REPC_PCODE_11,
219
    LDE_REPC_PCODE_12,
220
    LDE_REPC_PCODE_13,
221
    LDE_REPC_PCODE_14,
222
    LDE_REPC_PCODE_15,
223
    LDE_REPC_PCODE_16,
224
    LDE_REPC_PCODE_17,
225
    LDE_REPC_PCODE_18,
226
    LDE_REPC_PCODE_19,
227
    LDE_REPC_PCODE_20,
228
    LDE_REPC_PCODE_21,
229
    LDE_REPC_PCODE_22,
230
    LDE_REPC_PCODE_23,
231
    LDE_REPC_PCODE_24
232
};
233
234
const double txpwr_compensation[NUM_CH] = {
235
    0.0,
236
    0.035,
237
    0.0,
238
    0.0,
239
    0.065,
240
    0.0
241
};
242
243
244
#define NUM_16M_OFFSET  (37)
245
#define NUM_16M_OFFSETWB  (68)
246
#define NUM_64M_OFFSET  (26)
247
#define NUM_64M_OFFSETWB  (59)
248
249
const uint8_t chan_idxnb[NUM_CH_SUPPORTED] = {0, 0, 1, 2, 0, 3, 0, 0}; //only channels 1,2,3 and 5 are in the narrow band tables
250
const uint8_t chan_idxwb[NUM_CH_SUPPORTED] = {0, 0, 0, 0, 0, 0, 0, 1}; //only channels 4 and 7 are in in the wide band tables
251
252
//---------------------------------------------------------------------------------------------------------------------------
253
// Range Bias Correction TABLES of range values in integer units of 25 CM, for 8-bit unsigned storage, MUST END IN 255 !!!!!!
254
//---------------------------------------------------------------------------------------------------------------------------
255
256
// offsets to nearest centimeter for index 0, all rest are +1 cm per value
257
258
#define CM_OFFSET_16M_NB    (-23)   // for normal band channels at 16 MHz PRF
259
#define CM_OFFSET_16M_WB    (-28)   // for wider  band channels at 16 MHz PRF
260
#define CM_OFFSET_64M_NB    (-17)   // for normal band channels at 64 MHz PRF
261
#define CM_OFFSET_64M_WB    (-30)   // for wider  band channels at 64 MHz PRF
262
263
264
//---------------------------------------------------------------------------------------------------------------------------
265
// range25cm16PRFnb: Range Bias Correction table for narrow band channels at 16 MHz PRF, NB: !!!! each MUST END IN 255 !!!!
266
//---------------------------------------------------------------------------------------------------------------------------
267
268
const uint8_t range25cm16PRFnb[4][NUM_16M_OFFSET] =
269
{
270
    // ch 1 - range25cm16PRFnb
271
    {
272
           1,
273
           3,
274
           4,
275
           5,
276
           7,
277
           9,
278
          11,
279
          12,
280
          13,
281
          15,
282
          18,
283
          20,
284
          23,
285
          25,
286
          28,
287
          30,
288
          33,
289
          36,
290
          40,
291
          43,
292
          47,
293
          50,
294
          54,
295
          58,
296
          63,
297
          66,
298
          71,
299
          76,
300
          82,
301
          89,
302
          98,
303
         109,
304
         127,
305
         155,
306
         222,
307
         255,
308
         255
309
    },
310
311
    // ch 2 - range25cm16PRFnb
312
    {
313
           1,
314
           2,
315
           4,
316
           5,
317
           6,
318
           8,
319
           9,
320
          10,
321
          12,
322
          13,
323
          15,
324
          18,
325
          20,
326
          22,
327
          24,
328
          27,
329
          29,
330
          32,
331
          35,
332
          38,
333
          41,
334
          44,
335
          47,
336
          51,
337
          55,
338
          58,
339
          62,
340
          66,
341
          71,
342
          78,
343
          85,
344
          96,
345
         111,
346
         135,
347
         194,
348
         240,
349
         255
350
    },
351
352
    // ch 3 - range25cm16PRFnb
353
    {
354
           1,
355
           2,
356
           3,
357
           4,
358
           5,
359
           7,
360
           8,
361
           9,
362
          10,
363
          12,
364
          14,
365
          16,
366
          18,
367
          20,
368
          22,
369
          24,
370
          26,
371
          28,
372
          31,
373
          33,
374
          36,
375
          39,
376
          42,
377
          45,
378
          49,
379
          52,
380
          55,
381
          59,
382
          63,
383
          69,
384
          76,
385
          85,
386
          98,
387
         120,
388
         173,
389
         213,
390
         255
391
    },
392
393
    // ch 5 - range25cm16PRFnb
394
    {
395
           1,
396
           1,
397
           2,
398
           3,
399
           4,
400
           5,
401
           6,
402
           6,
403
           7,
404
           8,
405
           9,
406
          11,
407
          12,
408
          14,
409
          15,
410
          16,
411
          18,
412
          20,
413
          21,
414
          23,
415
          25,
416
          27,
417
          29,
418
          31,
419
          34,
420
          36,
421
          38,
422
          41,
423
          44,
424
          48,
425
          53,
426
          59,
427
          68,
428
          83,
429
         120,
430
         148,
431
         255
432
    }
433
}; // end range25cm16PRFnb
434
435
436
//---------------------------------------------------------------------------------------------------------------------------
437
// range25cm16PRFwb: Range Bias Correction table for wide band channels at 16 MHz PRF, NB: !!!! each MUST END IN 255 !!!!
438
//---------------------------------------------------------------------------------------------------------------------------
439
440
const uint8_t range25cm16PRFwb[2][NUM_16M_OFFSETWB] =
441
{
442
    // ch 4 - range25cm16PRFwb
443
    {
444
           7,
445
           7,
446
           8,
447
           9,
448
           9,
449
          10,
450
          11,
451
          11,
452
          12,
453
          13,
454
          14,
455
          15,
456
          16,
457
          17,
458
          18,
459
          19,
460
          20,
461
          21,
462
          22,
463
          23,
464
          24,
465
          26,
466
          27,
467
          28,
468
          30,
469
          31,
470
          32,
471
          34,
472
          36,
473
          38,
474
          40,
475
          42,
476
          44,
477
          46,
478
          48,
479
          50,
480
          52,
481
          55,
482
          57,
483
          59,
484
          61,
485
          63,
486
          66,
487
          68,
488
          71,
489
          74,
490
          78,
491
          81,
492
          85,
493
          89,
494
          94,
495
          99,
496
         104,
497
         110,
498
         116,
499
         123,
500
         130,
501
         139,
502
         150,
503
         164,
504
         182,
505
         207,
506
         238,
507
         255,
508
         255,
509
         255,
510
         255,
511
         255
512
    },
513
514
    // ch 7 - range25cm16PRFwb
515
    {
516
           4,
517
           5,
518
           5,
519
           5,
520
           6,
521
           6,
522
           7,
523
           7,
524
           7,
525
           8,
526
           9,
527
           9,
528
          10,
529
          10,
530
          11,
531
          11,
532
          12,
533
          13,
534
          13,
535
          14,
536
          15,
537
          16,
538
          17,
539
          17,
540
          18,
541
          19,
542
          20,
543
          21,
544
          22,
545
          23,
546
          25,
547
          26,
548
          27,
549
          29,
550
          30,
551
          31,
552
          32,
553
          34,
554
          35,
555
          36,
556
          38,
557
          39,
558
          40,
559
          42,
560
          44,
561
          46,
562
          48,
563
          50,
564
          52,
565
          55,
566
          58,
567
          61,
568
          64,
569
          68,
570
          72,
571
          75,
572
          80,
573
          85,
574
          92,
575
         101,
576
         112,
577
         127,
578
         147,
579
         168,
580
         182,
581
         194,
582
         205,
583
         255
584
    }
585
}; // end range25cm16PRFwb
586
587
//---------------------------------------------------------------------------------------------------------------------------
588
// range25cm64PRFnb: Range Bias Correction table for narrow band channels at 64 MHz PRF, NB: !!!! each MUST END IN 255 !!!!
589
//---------------------------------------------------------------------------------------------------------------------------
590
591
const uint8_t range25cm64PRFnb[4][NUM_64M_OFFSET] =
592
{
593
    // ch 1 - range25cm64PRFnb
594
    {
595
           1,
596
           2,
597
           2,
598
           3,
599
           4,
600
           5,
601
           7,
602
          10,
603
          13,
604
          16,
605
          19,
606
          22,
607
          24,
608
          27,
609
          30,
610
          32,
611
          35,
612
          38,
613
          43,
614
          48,
615
          56,
616
          78,
617
         101,
618
         120,
619
         157,
620
         255
621
    },
622
623
    // ch 2 - range25cm64PRFnb
624
    {
625
           1,
626
           2,
627
           2,
628
           3,
629
           4,
630
           4,
631
           6,
632
           9,
633
          12,
634
          14,
635
          17,
636
          19,
637
          21,
638
          24,
639
          26,
640
          28,
641
          31,
642
          33,
643
          37,
644
          42,
645
          49,
646
          68,
647
          89,
648
         105,
649
         138,
650
         255
651
    },
652
653
    // ch 3 - range25cm64PRFnb
654
    {
655
           1,
656
           1,
657
           2,
658
           3,
659
           3,
660
           4,
661
           5,
662
           8,
663
          10,
664
          13,
665
          15,
666
          17,
667
          19,
668
          21,
669
          23,
670
          25,
671
          27,
672
          30,
673
          33,
674
          37,
675
          44,
676
          60,
677
          79,
678
          93,
679
         122,
680
         255
681
    },
682
683
    // ch 5 - range25cm64PRFnb
684
    {
685
           1,
686
           1,
687
           1,
688
           2,
689
           2,
690
           3,
691
           4,
692
           6,
693
           7,
694
           9,
695
          10,
696
          12,
697
          13,
698
          15,
699
          16,
700
          17,
701
          19,
702
          21,
703
          23,
704
          26,
705
          30,
706
          42,
707
          55,
708
          65,
709
          85,
710
         255
711
    }
712
}; // end range25cm64PRFnb
713
714
//---------------------------------------------------------------------------------------------------------------------------
715
// range25cm64PRFwb: Range Bias Correction table for wide band channels at 64 MHz PRF, NB: !!!! each MUST END IN 255 !!!!
716
//---------------------------------------------------------------------------------------------------------------------------
717
718
const uint8_t range25cm64PRFwb[2][NUM_64M_OFFSETWB] =
719
{
720
    // ch 4 - range25cm64PRFwb
721
    {
722
           7,
723
           8,
724
           8,
725
           9,
726
           9,
727
          10,
728
          11,
729
          12,
730
          13,
731
          13,
732
          14,
733
          15,
734
          16,
735
          16,
736
          17,
737
          18,
738
          19,
739
          19,
740
          20,
741
          21,
742
          22,
743
          24,
744
          25,
745
          27,
746
          28,
747
          29,
748
          30,
749
          32,
750
          33,
751
          34,
752
          35,
753
          37,
754
          39,
755
          41,
756
          43,
757
          45,
758
          48,
759
          50,
760
          53,
761
          56,
762
          60,
763
          64,
764
          68,
765
          74,
766
          81,
767
          89,
768
          98,
769
         109,
770
         122,
771
         136,
772
         146,
773
         154,
774
         162,
775
         178,
776
         220,
777
         249,
778
         255,
779
         255,
780
         255
781
    },
782
783
    // ch 7 - range25cm64PRFwb
784
    {
785
           4,
786
           5,
787
           5,
788
           5,
789
           6,
790
           6,
791
           7,
792
           7,
793
           8,
794
           8,
795
           9,
796
           9,
797
          10,
798
          10,
799
          10,
800
          11,
801
          11,
802
          12,
803
          13,
804
          13,
805
          14,
806
          15,
807
          16,
808
          16,
809
          17,
810
          18,
811
          19,
812
          19,
813
          20,
814
          21,
815
          22,
816
          23,
817
          24,
818
          25,
819
          26,
820
          28,
821
          29,
822
          31,
823
          33,
824
          35,
825
          37,
826
          39,
827
          42,
828
          46,
829
          50,
830
          54,
831
          60,
832
          67,
833
          75,
834
          83,
835
          90,
836
          95,
837
         100,
838
         110,
839
         135,
840
         153,
841
         172,
842
         192,
843
         255
844
    }
845
}; // end range25cm64PRFwb
846
847
848
849
850
851
/*! ------------------------------------------------------------------------------------------------------------------
852
 * Function: dwt_getrangebias()
853
 *
854
 * Description: This function is used to return the range bias correction need for TWR with DW1000 units.
855
 *
856
 * input parameters:        
857
 * @param chan  - specifies the operating channel (e.g. 1, 2, 3, 4, 5, 6 or 7) 
858
 * @param range - the calculated distance before correction
859
 * @param prf        - this is the PRF e.g. DWT_PRF_16M or DWT_PRF_64M
860
 *
861
 * output parameters
862
 *
863
 * returns correction needed in meters
864
 */
865
double dwt_getrangebias(uint8_t chan, float range, uint8_t prf)
866
{
867
    //first get the lookup index that corresponds to given range for a particular channel at 16M PRF
868
    int i = 0 ;
869
    int chanIdx ;
870
    int cmoffseti ;                                 // integer number of CM offset
871
872
    double mOffset ;                                // final offset result in metres
873
874
    // NB: note we may get some small negitive values e.g. up to -50 cm.
875
876
    int rangeint25cm = (int) (range * 4.00) ;       // convert range to integer number of 25cm values.
877
878
    if (rangeint25cm > 255) rangeint25cm = 255 ;    // make sure it matches largest value in table (all tables end in 255 !!!!)
879
880
    if (prf == DWT_PRF_16M)
881
    {
882
        switch(chan)
883
        {
884
            case 4:
885
            case 7:
886
            {
887
                chanIdx = chan_idxwb[chan];
888
                while (rangeint25cm > range25cm16PRFwb[chanIdx][i]) i++ ;       // find index in table corresponding to range
889
                cmoffseti = i + CM_OFFSET_16M_WB ;                              // nearest centimeter correction
890
            }
891
            break;
892
            default:
893
            {
894
                chanIdx = chan_idxnb[chan];
895
                while (rangeint25cm > range25cm16PRFnb[chanIdx][i]) i++ ;       // find index in table corresponding to range
896
                cmoffseti = i + CM_OFFSET_16M_NB ;                              // nearest centimeter correction
897
            }
898
        }//end of switch
899
    }
900
    else // 64M PRF
901
    {
902
        switch(chan)
903
        {
904
            case 4:
905
            case 7:
906
            {
907
                chanIdx = chan_idxwb[chan];
908
                while (rangeint25cm > range25cm64PRFwb[chanIdx][i]) i++ ;       // find index in table corresponding to range
909
                cmoffseti = i + CM_OFFSET_64M_WB ;                              // nearest centimeter correction
910
            }
911
            break;
912
            default:
913
            {
914
                chanIdx = chan_idxnb[chan];
915
                while (rangeint25cm > range25cm64PRFnb[chanIdx][i]) i++ ;       // find index in table corresponding to range
916
                cmoffseti = i + CM_OFFSET_64M_NB ;                              // nearest centimeter correction
917
            }
918
        }//end of switch
919
    } // end else
920
921
922
    mOffset = (float) cmoffseti ;                                       // offset result in centimmetres
923
924
    mOffset *= 0.01 ;                                                   // convert to metres
925
926
    return (mOffset) ;
927
}
928
929
930
931
// -------------------------------------------------------------------------------------------------------------------
932
//
933
// Internal functions for controlling and configuring the device
934
//
935
// -------------------------------------------------------------------------------------------------------------------
936
937
// Enable and Configure specified clocks
938
void _dwt_enableclocks(int clocks) ;
939
// Configure the ucode (FP algorithm) parameters
940
void _dwt_configlde(int prf);
941
// Load ucode from OTP/ROM
942
void _dwt_loaducodefromrom(void);
943
// Read non-volatile memory
944
uint32_t _dwt_otpread(uint32_t address);
945
// Program the non-volatile memory
946
uint32_t _dwt_otpprogword32(uint32_t data, uint16_t address);
947
// Upload the device configuration into always on memory
948
void _dwt_aonarrayupload(void);
949
// -------------------------------------------------------------------------------------------------------------------
950
951
/*!
952
 * Static data for DW1000 DecaWave Transceiver control
953
 */
954
955
static dwt_local_data_t dw1000local[DWT_NUM_DW_DEV] ; // Static local device data, can be an array to support multiple DW1000 testing applications/platforms
956
static dwt_local_data_t *pdw1000local = dw1000local ; // Static local data structure pointer
957
958
959
/*! ------------------------------------------------------------------------------------------------------------------
960
 * @fn dwt_setdevicedataptr()
961
 *
962
 * @brief This function sets the local data structure pointer to point to the structure in the local array as given by the index.
963
 *
964
 * input parameters
965
 * @param index    - selects the array object to point to. Must be within the array bounds, i.e. < DWT_NUM_DW_DEV
966
 *
967
 * output parameters
968
 *
969
 * returns DWT_SUCCESS for success, or DWT_ERROR for error
970
 */
971
int dwt_setdevicedataptr(unsigned int index)
972
{
973
    // Check the index is within the array bounds
974
    if (DWT_NUM_DW_DEV > index) // return error if index outside the array bounds
975
    {
976
        return DWT_ERROR ;
977
    }
978
979
    pdw1000local = &dw1000local[index];
980
981
    return DWT_SUCCESS ;
982
}
983
984
/*! ------------------------------------------------------------------------------------------------------------------
985
 * @fn dwt_initialise()
986
 *
987
 * @brief This function initiates communications with the DW1000 transceiver
988
 * and reads its DEV_ID register (address 0x00) to verify the IC is one supported
989
 * by this software (e.g. DW1000 32-bit device ID value is 0xDECA0130).  Then it
990
 * does any initial once only device configurations needed for use and initialises
991
 * as necessary any static data items belonging to this low-level driver.
992
 *
993
 * NOTES:
994
 * 1.this function needs to be run before dwt_configuresleep, also the SPI frequency has to be < 3MHz
995
 * 2.it also reads and applies LDO tune and crystal trim values from OTP memory
996
 *
997
 * input parameters
998
 * @param config    -   specifies what configuration to load
999
 *                  DWT_LOADUCODE     0x1 - load the LDE microcode from ROM - enabled accurate RX timestamp
1000
 *                  DWT_LOADNONE      0x0 - do not load any values from OTP memory
1001
 *
1002
 * output parameters
1003
 *
1004
 * returns DWT_SUCCESS for success, or DWT_ERROR for error
1005
 */
1006
// OTP addresses definitions
1007
#define LDOTUNE_ADDRESS (0x04)
1008
#define PARTID_ADDRESS (0x06)
1009
#define LOTID_ADDRESS  (0x07)
1010
#define VBAT_ADDRESS   (0x08)
1011
#define VTEMP_ADDRESS  (0x09)
1012
#define XTRIM_ADDRESS  (0x1E)
1013
1014 33f54213 Cung Sang
int dwt_initialise(const uint16_t config, DW1000Driver* drv)
1015 69a601a5 Cung Sang
{
1016
    uint16_t otp_addr = 0;
1017
    uint32_t ldo_tune = 0;
1018
1019
    pdw1000local->dblbuffon = 0; // Double buffer mode off by default
1020
    pdw1000local->wait4resp = 0;
1021
    pdw1000local->sleep_mode = 0;
1022
1023
    pdw1000local->cbTxDone = NULL;
1024
    pdw1000local->cbRxOk = NULL;
1025
    pdw1000local->cbRxTo = NULL;
1026
    pdw1000local->cbRxErr = NULL;
1027
1028 33f54213 Cung Sang
    pdw1000local->driver = drv;  // TODO:
1029 69a601a5 Cung Sang
1030
    // Read and validate device ID return -1 if not recognised
1031
    if (DWT_DEVICE_ID != dwt_readdevid()) // MP IC ONLY (i.e. DW1000) FOR THIS CODE
1032
    {
1033
        return DWT_ERROR ;
1034
    }
1035
1036
    // Make sure the device is completely reset before starting initialisation
1037
    dwt_softreset();
1038
1039
    _dwt_enableclocks(FORCE_SYS_XTI); // NOTE: set system clock to XTI - this is necessary to make sure the values read by _dwt_otpread are reliable
1040
1041
    // Configure the CPLL lock detect
1042
    dwt_write8bitoffsetreg(EXT_SYNC_ID, EC_CTRL_OFFSET, EC_CTRL_PLLLCK);
1043
1044
    // Read OTP revision number
1045
    otp_addr = _dwt_otpread(XTRIM_ADDRESS) & 0xffff;        // Read 32 bit value, XTAL trim val is in low octet-0 (5 bits)
1046
    pdw1000local->otprev = (otp_addr >> 8) & 0xff;            // OTP revision is next byte
1047
1048
    // Load LDO tune from OTP and kick it if there is a value actually programmed.
1049
    ldo_tune = _dwt_otpread(LDOTUNE_ADDRESS);
1050
    if((ldo_tune & 0xFF) != 0)
1051
    {
1052
        // Kick LDO tune
1053
        dwt_write8bitoffsetreg(OTP_IF_ID, OTP_SF, OTP_SF_LDO_KICK); // Set load LDE kick bit
1054
        pdw1000local->sleep_mode |= AON_WCFG_ONW_LLDO; // LDO tune must be kicked at wake-up
1055
    }
1056
1057
    // Load Part and Lot ID from OTP
1058
    pdw1000local->partID = _dwt_otpread(PARTID_ADDRESS);
1059
    pdw1000local->lotID = _dwt_otpread(LOTID_ADDRESS);
1060
1061
    // XTAL trim value is set in OTP for DW1000 module and EVK/TREK boards but that might not be the case in a custom design
1062
    pdw1000local->init_xtrim = otp_addr & 0x1F;
1063
    if (!pdw1000local->init_xtrim) // A value of 0 means that the crystal has not been trimmed
1064
    {
1065
        pdw1000local->init_xtrim = FS_XTALT_MIDRANGE ; // Set to mid-range if no calibration value inside
1066
    }
1067
    // Configure XTAL trim
1068
    dwt_setxtaltrim(pdw1000local->init_xtrim);
1069
1070
    // Load leading edge detect code
1071
    if(config & DWT_LOADUCODE)
1072
    {
1073
        _dwt_loaducodefromrom();
1074
        pdw1000local->sleep_mode |= AON_WCFG_ONW_LLDE; // microcode must be loaded at wake-up
1075
    }
1076
    else // Should disable the LDERUN enable bit in 0x36, 0x4
1077
    {
1078
        uint16_t rega = dwt_read16bitoffsetreg(PMSC_ID, PMSC_CTRL1_OFFSET+1) ;
1079
        rega &= 0xFDFF ; // Clear LDERUN bit
1080
        dwt_write16bitoffsetreg(PMSC_ID, PMSC_CTRL1_OFFSET+1, rega) ;
1081
    }
1082
1083
    _dwt_enableclocks(ENABLE_ALL_SEQ); // Enable clocks for sequencing
1084
1085
    // The 3 bits in AON CFG1 register must be cleared to ensure proper operation of the DW1000 in DEEPSLEEP mode.
1086
    dwt_write8bitoffsetreg(AON_ID, AON_CFG1_OFFSET, 0x00);
1087
1088
    // Read system register / store local copy
1089
    pdw1000local->sysCFGreg = dwt_read32bitreg(SYS_CFG_ID) ; // Read sysconfig register
1090
1091
    return DWT_SUCCESS ;
1092
1093
} // end dwt_initialise()
1094
1095
/*! ------------------------------------------------------------------------------------------------------------------
1096
 * @fn dwt_otprevision()
1097
 *
1098
 * @brief This is used to return the read OTP revision
1099
 *
1100
 * NOTE: dwt_initialise() must be called prior to this function so that it can return a relevant value.
1101
 *
1102
 * input parameters
1103
 *
1104
 * output parameters
1105
 *
1106
 * returns the read OTP revision value
1107
 */
1108
uint8_t dwt_otprevision(void)
1109
{
1110
    return pdw1000local->otprev ;
1111
}
1112
1113
/*! ------------------------------------------------------------------------------------------------------------------
1114
 * @fn dwt_setfinegraintxseq()
1115
 *
1116
 * @brief This function enables/disables the fine grain TX sequencing (enabled by default).
1117
 *
1118
 * input parameters
1119
 * @param enable - 1 to enable fine grain TX sequencing, 0 to disable it.
1120
 *
1121
 * output parameters none
1122
 *
1123
 * no return value
1124
 */
1125
void dwt_setfinegraintxseq(int enable)
1126
{
1127
    if (enable)
1128
    {
1129
        dwt_write16bitoffsetreg(PMSC_ID, PMSC_TXFINESEQ_OFFSET, PMSC_TXFINESEQ_ENABLE);
1130
    }
1131
    else
1132
    {
1133
        dwt_write16bitoffsetreg(PMSC_ID, PMSC_TXFINESEQ_OFFSET, PMSC_TXFINESEQ_DISABLE);
1134
    }
1135
}
1136
1137
/*! ------------------------------------------------------------------------------------------------------------------
1138
 * @fn dwt_setlnapamode()
1139
 *
1140
 * @brief This is used to enable GPIO for external LNA or PA functionality - HW dependent, consult the DW1000 User Manual.
1141
 *        This can also be used for debug as enabling TX and RX GPIOs is quite handy to monitor DW1000's activity.
1142
 *
1143
 * NOTE: Enabling PA functionality requires that fine grain TX sequencing is deactivated. This can be done using
1144
 *       dwt_setfinegraintxseq().
1145
 *
1146
 * input parameters
1147
 * @param lna - 1 to enable LNA functionality, 0 to disable it
1148
 * @param pa - 1 to enable PA functionality, 0 to disable it
1149
 *
1150
 * output parameters
1151
 *
1152
 * no return value
1153
 */
1154
void dwt_setlnapamode(int lna, int pa)
1155
{
1156
    uint32_t gpio_mode = dwt_read32bitoffsetreg(GPIO_CTRL_ID, GPIO_MODE_OFFSET);
1157
    gpio_mode &= ~(GPIO_MSGP4_MASK | GPIO_MSGP5_MASK | GPIO_MSGP6_MASK);
1158
    if (lna)
1159
    {
1160
        gpio_mode |= GPIO_PIN6_EXTRXE;
1161
    }
1162
    if (pa)
1163
    {
1164
        gpio_mode |= (GPIO_PIN5_EXTTXE | GPIO_PIN4_EXTPA);
1165
    }
1166
    dwt_write32bitoffsetreg(GPIO_CTRL_ID, GPIO_MODE_OFFSET, gpio_mode);
1167
}
1168
1169
/*! ------------------------------------------------------------------------------------------------------------------
1170
 * @fn dwt_setgpiodirection()
1171
 *
1172
 * @brief This is used to set GPIO direction as an input (1) or output (0)
1173
 *
1174
 * input parameters
1175
 * @param gpioNum    -   this is the GPIO to configure - see GxM0... GxM8 in the deca_regs.h file
1176
 * @param direction  -   this sets the GPIO direction - see GxP0... GxP8 in the deca_regs.h file
1177
 *
1178
 * output parameters
1179
 *
1180
 * no return value
1181
 */
1182
void dwt_setgpiodirection(uint32_t gpioNum, uint32_t direction)
1183
{
1184
    uint8_t buf[GPIO_DIR_LEN];
1185
    uint32_t command = direction | gpioNum;
1186
1187
    buf[0] = command & 0xff;
1188
    buf[1] = (command >> 8) & 0xff;
1189
    buf[2] = (command >> 16) & 0xff;
1190
1191
    dwt_writetodevice(GPIO_CTRL_ID, GPIO_DIR_OFFSET, GPIO_DIR_LEN, buf);
1192
}
1193
1194
/*! ------------------------------------------------------------------------------------------------------------------
1195
 * @fn dwt_setgpiovalue()
1196
 *
1197
 * @brief This is used to set GPIO value as (1) or (0) only applies if the GPIO is configured as output
1198
 *
1199
 * input parameters
1200
 * @param gpioNum    -   this is the GPIO to configure - see GxM0... GxM8 in the deca_regs.h file
1201
 * @param value  -   this sets the GPIO value - see GDP0... GDP8 in the deca_regs.h file
1202
 *
1203
 * output parameters
1204
 *
1205
 * no return value
1206
 */
1207
void dwt_setgpiovalue(uint32_t gpioNum, uint32_t value)
1208
{
1209
    uint8_t buf[GPIO_DOUT_LEN];
1210
    uint32_t command = value | gpioNum;
1211
1212
    buf[0] = command & 0xff;
1213
    buf[1] = (command >> 8) & 0xff;
1214
    buf[2] = (command >> 16) & 0xff;
1215
1216
    dwt_writetodevice(GPIO_CTRL_ID, GPIO_DOUT_OFFSET, GPIO_DOUT_LEN, buf);
1217
}
1218
1219
/*! ------------------------------------------------------------------------------------------------------------------
1220
 * @fn dwt_getpartid()
1221
 *
1222
 * @brief This is used to return the read part ID of the device
1223
 *
1224
 * NOTE: dwt_initialise() must be called prior to this function so that it can return a relevant value.
1225
 *
1226
 * input parameters
1227
 *
1228
 * output parameters
1229
 *
1230
 * returns the 32 bit part ID value as programmed in the factory
1231
 */
1232
uint32_t dwt_getpartid(void)
1233
{
1234
    return pdw1000local->partID;
1235
}
1236
1237
/*! ------------------------------------------------------------------------------------------------------------------
1238
 * @fn dwt_getlotid()
1239
 *
1240
 * @brief This is used to return the read lot ID of the device
1241
 *
1242
 * NOTE: dwt_initialise() must be called prior to this function so that it can return a relevant value.
1243
 *
1244
 * input parameters
1245
 *
1246
 * output parameters
1247
 *
1248
 * returns the 32 bit lot ID value as programmed in the factory
1249
 */
1250
uint32_t dwt_getlotid(void)
1251
{
1252
    return pdw1000local->lotID;
1253
}
1254
1255
/*! ------------------------------------------------------------------------------------------------------------------
1256
 * @fn dwt_readdevid()
1257
 *
1258
 * @brief This is used to return the read device type and revision information of the DW1000 device (MP part is 0xDECA0130)
1259
 *
1260
 * input parameters
1261
 *
1262
 * output parameters
1263
 *
1264
 * returns the read value which for DW1000 is 0xDECA0130
1265
 */
1266
uint32_t dwt_readdevid(void)
1267
{
1268
    return dwt_read32bitoffsetreg(DEV_ID_ID,0);
1269
}
1270
1271
/*! ------------------------------------------------------------------------------------------------------------------
1272
 * @fn dwt_configuretxrf()
1273
 *
1274
 * @brief This function provides the API for the configuration of the TX spectrum
1275
 * including the power and pulse generator delay. The input is a pointer to the data structure
1276
 * of type dwt_txconfig_t that holds all the configurable items.
1277
 *
1278
 * input parameters
1279
 * @param config    -   pointer to the txrf configuration structure, which contains the tx rf config data
1280
 *
1281
 * output parameters
1282
 *
1283
 * no return value
1284
 */
1285
void dwt_configuretxrf(dwt_txconfig_t* config)
1286
{
1287
1288
    // Configure RF TX PG_DELAY
1289
    dwt_write8bitoffsetreg(TX_CAL_ID, TC_PGDELAY_OFFSET, config->PGdly);
1290
1291
    // Configure TX power
1292
    dwt_write32bitreg(TX_POWER_ID, config->power);
1293
1294
}
1295
1296
/*! ------------------------------------------------------------------------------------------------------------------
1297
 * @fn dwt_configure()
1298
 *
1299
 * @brief This function provides the main API for the configuration of the
1300
 * DW1000 and this low-level driver.  The input is a pointer to the data structure
1301
 * of type dwt_config_t that holds all the configurable items.
1302
 * The dwt_config_t structure shows which ones are supported
1303
 *
1304
 * input parameters
1305
 * @param config    -   pointer to the configuration structure, which contains the device configuration data.
1306
 *
1307
 * output parameters
1308
 *
1309
 * no return value
1310
 */
1311
void dwt_configure(dwt_config_t *config)
1312
{
1313
    uint8_t nsSfd_result  = 0;
1314
    uint8_t useDWnsSFD = 0;
1315
    uint8_t chan = config->chan ;
1316
    uint32_t regval ;
1317
    uint16_t reg16 = lde_replicaCoeff[config->rxCode];
1318
    uint8_t prfIndex = config->prf - DWT_PRF_16M;
1319
    uint8_t bw = ((chan == 4) || (chan == 7)) ? 1 : 0 ; // Select wide or narrow band
1320
1321
#ifdef DWT_API_ERROR_CHECK
1322
    assert(config->dataRate <= DWT_BR_6M8);
1323
    assert(config->rxPAC <= DWT_PAC64);
1324
    assert((chan >= 1) && (chan <= 7) && (chan != 6));
1325
    assert(((config->prf == DWT_PRF_64M) && (config->txCode >= 9) && (config->txCode <= 24))
1326
           || ((config->prf == DWT_PRF_16M) && (config->txCode >= 1) && (config->txCode <= 8)));
1327
    assert(((config->prf == DWT_PRF_64M) && (config->rxCode >= 9) && (config->rxCode <= 24))
1328
           || ((config->prf == DWT_PRF_16M) && (config->rxCode >= 1) && (config->rxCode <= 8)));
1329
    assert((config->txPreambLength == DWT_PLEN_64) || (config->txPreambLength == DWT_PLEN_128) || (config->txPreambLength == DWT_PLEN_256)
1330
           || (config->txPreambLength == DWT_PLEN_512) || (config->txPreambLength == DWT_PLEN_1024) || (config->txPreambLength == DWT_PLEN_1536)
1331
           || (config->txPreambLength == DWT_PLEN_2048) || (config->txPreambLength == DWT_PLEN_4096));
1332
    assert((config->phrMode == DWT_PHRMODE_STD) || (config->phrMode == DWT_PHRMODE_EXT));
1333
#endif
1334
1335
    // For 110 kbps we need a special setup
1336
    if(DWT_BR_110K == config->dataRate)
1337
    {
1338
        pdw1000local->sysCFGreg |= SYS_CFG_RXM110K ;
1339
        reg16 >>= 3; // lde_replicaCoeff must be divided by 8
1340
    }
1341
    else
1342
    {
1343
        pdw1000local->sysCFGreg &= (~SYS_CFG_RXM110K) ;
1344
    }
1345
1346
    pdw1000local->longFrames = config->phrMode ;
1347
1348
    pdw1000local->sysCFGreg &= ~SYS_CFG_PHR_MODE_11;
1349
    pdw1000local->sysCFGreg |= (SYS_CFG_PHR_MODE_11 & (config->phrMode << SYS_CFG_PHR_MODE_SHFT));
1350
1351
    dwt_write32bitreg(SYS_CFG_ID,pdw1000local->sysCFGreg) ;
1352
    // Set the lde_replicaCoeff
1353
    dwt_write16bitoffsetreg(LDE_IF_ID, LDE_REPC_OFFSET, reg16) ;
1354
1355
    _dwt_configlde(prfIndex);
1356
1357
    // Configure PLL2/RF PLL block CFG/TUNE (for a given channel)
1358
    dwt_write32bitoffsetreg(FS_CTRL_ID, FS_PLLCFG_OFFSET, fs_pll_cfg[chan_idx[chan]]);
1359
    dwt_write8bitoffsetreg(FS_CTRL_ID, FS_PLLTUNE_OFFSET, fs_pll_tune[chan_idx[chan]]);
1360
1361
    // Configure RF RX blocks (for specified channel/bandwidth)
1362
    dwt_write8bitoffsetreg(RF_CONF_ID, RF_RXCTRLH_OFFSET, rx_config[bw]);
1363
1364
    // Configure RF TX blocks (for specified channel and PRF)
1365
    // Configure RF TX control
1366
    dwt_write32bitoffsetreg(RF_CONF_ID, RF_TXCTRL_OFFSET, tx_config[chan_idx[chan]]);
1367
1368
    // Configure the baseband parameters (for specified PRF, bit rate, PAC, and SFD settings)
1369
    // DTUNE0
1370
    dwt_write16bitoffsetreg(DRX_CONF_ID, DRX_TUNE0b_OFFSET, sftsh[config->dataRate][config->nsSFD]);
1371
1372
    // DTUNE1
1373
    dwt_write16bitoffsetreg(DRX_CONF_ID, DRX_TUNE1a_OFFSET, dtune1[prfIndex]);
1374
1375
    if(config->dataRate == DWT_BR_110K)
1376
    {
1377
        dwt_write16bitoffsetreg(DRX_CONF_ID, DRX_TUNE1b_OFFSET, DRX_TUNE1b_110K);
1378
    }
1379
    else
1380
    {
1381
        if(config->txPreambLength == DWT_PLEN_64)
1382
        {
1383
            dwt_write16bitoffsetreg(DRX_CONF_ID, DRX_TUNE1b_OFFSET, DRX_TUNE1b_6M8_PRE64);
1384
            dwt_write8bitoffsetreg(DRX_CONF_ID, DRX_TUNE4H_OFFSET, DRX_TUNE4H_PRE64);
1385
        }
1386
        else
1387
        {
1388
            dwt_write16bitoffsetreg(DRX_CONF_ID, DRX_TUNE1b_OFFSET, DRX_TUNE1b_850K_6M8);
1389
            dwt_write8bitoffsetreg(DRX_CONF_ID, DRX_TUNE4H_OFFSET, DRX_TUNE4H_PRE128PLUS);
1390
        }
1391
    }
1392
1393
    // DTUNE2
1394
    dwt_write32bitoffsetreg(DRX_CONF_ID, DRX_TUNE2_OFFSET, digital_bb_config[prfIndex][config->rxPAC]);
1395
1396
    // DTUNE3 (SFD timeout)
1397
    // Don't allow 0 - SFD timeout will always be enabled
1398
    if(config->sfdTO == 0)
1399
    {
1400
        config->sfdTO = DWT_SFDTOC_DEF;
1401
    }
1402
    dwt_write16bitoffsetreg(DRX_CONF_ID, DRX_SFDTOC_OFFSET, config->sfdTO);
1403
1404
    // Configure AGC parameters
1405
    dwt_write32bitoffsetreg( AGC_CFG_STS_ID, 0xC, agc_config.lo32);
1406
    dwt_write16bitoffsetreg( AGC_CFG_STS_ID, 0x4, agc_config.target[prfIndex]);
1407
1408
    // Set (non-standard) user SFD for improved performance,
1409
    if(config->nsSFD)
1410
    {
1411
        // Write non standard (DW) SFD length
1412
        dwt_write8bitoffsetreg(USR_SFD_ID, 0x00, dwnsSFDlen[config->dataRate]);
1413
        nsSfd_result = 3 ;
1414
        useDWnsSFD = 1 ;
1415
    }
1416
    regval =  (CHAN_CTRL_TX_CHAN_MASK & (chan << CHAN_CTRL_TX_CHAN_SHIFT)) | // Transmit Channel
1417
              (CHAN_CTRL_RX_CHAN_MASK & (chan << CHAN_CTRL_RX_CHAN_SHIFT)) | // Receive Channel
1418
              (CHAN_CTRL_RXFPRF_MASK & (config->prf << CHAN_CTRL_RXFPRF_SHIFT)) | // RX PRF
1419
              ((CHAN_CTRL_TNSSFD|CHAN_CTRL_RNSSFD) & (nsSfd_result << CHAN_CTRL_TNSSFD_SHIFT)) | // nsSFD enable RX&TX
1420
              (CHAN_CTRL_DWSFD & (useDWnsSFD << CHAN_CTRL_DWSFD_SHIFT)) | // Use DW nsSFD
1421
              (CHAN_CTRL_TX_PCOD_MASK & (config->txCode << CHAN_CTRL_TX_PCOD_SHIFT)) | // TX Preamble Code
1422
              (CHAN_CTRL_RX_PCOD_MASK & (config->rxCode << CHAN_CTRL_RX_PCOD_SHIFT)) ; // RX Preamble Code
1423
1424
    dwt_write32bitreg(CHAN_CTRL_ID,regval) ;
1425
1426
    // Set up TX Preamble Size, PRF and Data Rate
1427
    pdw1000local->txFCTRL = ((config->txPreambLength | config->prf) << TX_FCTRL_TXPRF_SHFT) | (config->dataRate << TX_FCTRL_TXBR_SHFT);
1428
    dwt_write32bitreg(TX_FCTRL_ID, pdw1000local->txFCTRL);
1429
1430
    // The SFD transmit pattern is initialised by the DW1000 upon a user TX request, but (due to an IC issue) it is not done for an auto-ACK TX. The
1431
    // SYS_CTRL write below works around this issue, by simultaneously initiating and aborting a transmission, which correctly initialises the SFD
1432
    // after its configuration or reconfiguration.
1433
    // This issue is not documented at the time of writing this code. It should be in next release of DW1000 User Manual (v2.09, from July 2016).
1434
    dwt_write8bitoffsetreg(SYS_CTRL_ID, SYS_CTRL_OFFSET, SYS_CTRL_TXSTRT | SYS_CTRL_TRXOFF); // Request TX start and TRX off at the same time
1435
} // end dwt_configure()
1436
1437
/*! ------------------------------------------------------------------------------------------------------------------
1438
 * @fn dwt_setrxantennadelay()
1439
 *
1440
 * @brief This API function writes the antenna delay (in time units) to RX registers
1441
 *
1442
 * input parameters:
1443
 * @param rxDelay - this is the total (RX) antenna delay value, which
1444
 *                          will be programmed into the RX register
1445
 *
1446
 * output parameters
1447
 *
1448
 * no return value
1449
 */
1450
void dwt_setrxantennadelay(uint16_t rxDelay)
1451
{
1452
    // Set the RX antenna delay for auto TX timestamp adjustment
1453
    dwt_write16bitoffsetreg(LDE_IF_ID, LDE_RXANTD_OFFSET, rxDelay);
1454
}
1455
1456
/*! ------------------------------------------------------------------------------------------------------------------
1457
 * @fn dwt_settxantennadelay()
1458
 *
1459
 * @brief This API function writes the antenna delay (in time units) to TX registers
1460
 *
1461
 * input parameters:
1462
 * @param txDelay - this is the total (TX) antenna delay value, which
1463
 *                          will be programmed into the TX delay register
1464
 *
1465
 * output parameters
1466
 *
1467
 * no return value
1468
 */
1469
void dwt_settxantennadelay(uint16_t txDelay)
1470
{
1471
    // Set the TX antenna delay for auto TX timestamp adjustment
1472
    dwt_write16bitoffsetreg(TX_ANTD_ID, TX_ANTD_OFFSET, txDelay);
1473
}
1474
1475
/*! ------------------------------------------------------------------------------------------------------------------
1476
 * @fn dwt_writetxdata()
1477
 *
1478
 * @brief This API function writes the supplied TX data into the DW1000's
1479
 * TX buffer.  The input parameters are the data length in bytes and a pointer
1480
 * to those data bytes.
1481
 *
1482
 * input parameters
1483
 * @param txFrameLength  - This is the total frame length, including the two byte CRC.
1484
 *                         Note: this is the length of TX message (including the 2 byte CRC) - max is 1023
1485
 *                         standard PHR mode allows up to 127 bytes
1486
 *                         if > 127 is programmed, DWT_PHRMODE_EXT needs to be set in the phrMode configuration
1487
 *                         see dwt_configure function
1488
 * @param txFrameBytes   - Pointer to the user’s buffer containing the data to send.
1489
 * @param txBufferOffset - This specifies an offset in the DW1000’s TX Buffer at which to start writing data.
1490
 *
1491
 * output parameters
1492
 *
1493
 * returns DWT_SUCCESS for success, or DWT_ERROR for error
1494
 */
1495
int dwt_writetxdata(uint16_t txFrameLength, uint8_t *txFrameBytes, uint16_t txBufferOffset)
1496
{
1497
#ifdef DWT_API_ERROR_CHECK
1498
    assert(txFrameLength >= 2);
1499
    assert((pdw1000local->longFrames && (txFrameLength <= 1023)) || (txFrameLength <= 127));
1500
    assert((txBufferOffset + txFrameLength) <= 1024);
1501
#endif
1502
1503
    if ((txBufferOffset + txFrameLength) <= 1024)
1504
    {
1505
        // Write the data to the IC TX buffer, (-2 bytes for auto generated CRC)
1506
        dwt_writetodevice( TX_BUFFER_ID, txBufferOffset, txFrameLength-2, txFrameBytes);
1507
        return DWT_SUCCESS;
1508
    }
1509
    else
1510
    {
1511
        return DWT_ERROR;
1512
    }
1513
} // end dwt_writetxdata()
1514
1515
/*! ------------------------------------------------------------------------------------------------------------------
1516
 * @fn dwt_writetxfctrl()
1517
 *
1518
 * @brief This API function configures the TX frame control register before the transmission of a frame
1519
 *
1520
 * input parameters:
1521
 * @param txFrameLength - this is the length of TX message (including the 2 byte CRC) - max is 1023
1522
 *                              NOTE: standard PHR mode allows up to 127 bytes
1523
 *                              if > 127 is programmed, DWT_PHRMODE_EXT needs to be set in the phrMode configuration
1524
 *                              see dwt_configure function
1525
 * @param txBufferOffset - the offset in the tx buffer to start writing the data
1526
 * @param ranging - 1 if this is a ranging frame, else 0
1527
 *
1528
 * output parameters
1529
 *
1530
 * no return value
1531
 */
1532
void dwt_writetxfctrl(uint16_t txFrameLength, uint16_t txBufferOffset, int ranging)
1533
{
1534
1535
#ifdef DWT_API_ERROR_CHECK
1536
    assert((pdw1000local->longFrames && (txFrameLength <= 1023)) || (txFrameLength <= 127));
1537
#endif
1538
1539
    // Write the frame length to the TX frame control register
1540
    // pdw1000local->txFCTRL has kept configured bit rate information
1541
    uint32_t reg32 = pdw1000local->txFCTRL | txFrameLength | (txBufferOffset << TX_FCTRL_TXBOFFS_SHFT) | (ranging << TX_FCTRL_TR_SHFT);
1542
    dwt_write32bitreg(TX_FCTRL_ID, reg32);
1543
} // end dwt_writetxfctrl()
1544
1545
1546
/*! ------------------------------------------------------------------------------------------------------------------
1547
 * @fn dwt_readrxdata()
1548
 *
1549
 * @brief This is used to read the data from the RX buffer, from an offset location give by offset parameter
1550
 *
1551
 * input parameters
1552
 * @param buffer - the buffer into which the data will be read
1553
 * @param length - the length of data to read (in bytes)
1554
 * @param rxBufferOffset - the offset in the rx buffer from which to read the data
1555
 *
1556
 * output parameters
1557
 *
1558
 * no return value
1559
 */
1560
void dwt_readrxdata(uint8_t *buffer, uint16_t length, uint16_t rxBufferOffset)
1561
{
1562
    dwt_readfromdevice(RX_BUFFER_ID,rxBufferOffset,length,buffer) ;
1563
}
1564
1565
/*! ------------------------------------------------------------------------------------------------------------------
1566
 * @fn dwt_readaccdata()
1567
 *
1568
 * @brief This is used to read the data from the Accumulator buffer, from an offset location give by offset parameter
1569
 *
1570
 * NOTE: Because of an internal memory access delay when reading the accumulator the first octet output is a dummy octet
1571
 *       that should be discarded. This is true no matter what sub-index the read begins at.
1572
 *
1573
 * input parameters
1574
 * @param buffer - the buffer into which the data will be read
1575
 * @param length - the length of data to read (in bytes)
1576
 * @param accOffset - the offset in the acc buffer from which to read the data
1577
 *
1578
 * output parameters
1579
 *
1580
 * no return value
1581
 */
1582
void dwt_readaccdata(uint8_t *buffer, uint16_t len, uint16_t accOffset)
1583
{
1584
    // Force on the ACC clocks if we are sequenced
1585
    _dwt_enableclocks(READ_ACC_ON);
1586
1587
    dwt_readfromdevice(ACC_MEM_ID,accOffset,len,buffer) ;
1588
1589
    _dwt_enableclocks(READ_ACC_OFF); // Revert clocks back
1590
}
1591
1592
/*! ------------------------------------------------------------------------------------------------------------------
1593
 * @fn dwt_readdiagnostics()
1594
 *
1595
 * @brief this function reads the RX signal quality diagnostic data
1596
 *
1597
 * input parameters
1598
 * @param diagnostics - diagnostic structure pointer, this will contain the diagnostic data read from the DW1000
1599
 *
1600
 * output parameters
1601
 *
1602
 * no return value
1603
 */
1604
void dwt_readdiagnostics(dwt_rxdiag_t *diagnostics)
1605
{
1606
    // Read the HW FP index
1607
    diagnostics->firstPath = dwt_read16bitoffsetreg(RX_TIME_ID, RX_TIME_FP_INDEX_OFFSET);
1608
1609
    // LDE diagnostic data
1610
    diagnostics->maxNoise = dwt_read16bitoffsetreg(LDE_IF_ID, LDE_THRESH_OFFSET);
1611
1612
    // Read all 8 bytes in one SPI transaction
1613
    dwt_readfromdevice(RX_FQUAL_ID, 0x0, 8, (uint8_t*)&diagnostics->stdNoise);
1614
1615
    diagnostics->firstPathAmp1 = dwt_read16bitoffsetreg(RX_TIME_ID, RX_TIME_FP_AMPL1_OFFSET);
1616
1617
    diagnostics->rxPreamCount = (dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXPACC_MASK) >> RX_FINFO_RXPACC_SHIFT  ;
1618
}
1619
1620
/*! ------------------------------------------------------------------------------------------------------------------
1621
 * @fn dwt_readtxtimestamp()
1622
 *
1623
 * @brief This is used to read the TX timestamp (adjusted with the programmed antenna delay)
1624
 *
1625
 * input parameters
1626
 * @param timestamp - a pointer to a 5-byte buffer which will store the read TX timestamp time
1627
 *
1628
 * output parameters - the timestamp buffer will contain the value after the function call
1629
 *
1630
 * no return value
1631
 */
1632
void dwt_readtxtimestamp(uint8_t * timestamp)
1633
{
1634
    dwt_readfromdevice(TX_TIME_ID, TX_TIME_TX_STAMP_OFFSET, TX_TIME_TX_STAMP_LEN, timestamp) ; // Read bytes directly into buffer
1635
}
1636
1637
/*! ------------------------------------------------------------------------------------------------------------------
1638
 * @fn dwt_readtxtimestamphi32()
1639
 *
1640
 * @brief This is used to read the high 32-bits of the TX timestamp (adjusted with the programmed antenna delay)
1641
 *
1642
 * input parameters
1643
 *
1644
 * output parameters
1645
 *
1646
 * returns high 32-bits of TX timestamp
1647
 */
1648
uint32_t dwt_readtxtimestamphi32(void)
1649
{
1650
    return dwt_read32bitoffsetreg(TX_TIME_ID, 1); // Offset is 1 to get the 4 upper bytes out of 5
1651
}
1652
1653
/*! ------------------------------------------------------------------------------------------------------------------
1654
 * @fn dwt_readtxtimestamplo32()
1655
 *
1656
 * @brief This is used to read the low 32-bits of the TX timestamp (adjusted with the programmed antenna delay)
1657
 *
1658
 * input parameters
1659
 *
1660
 * output parameters
1661
 *
1662
 * returns low 32-bits of TX timestamp
1663
 */
1664
uint32_t dwt_readtxtimestamplo32(void)
1665
{
1666
    return dwt_read32bitreg(TX_TIME_ID); // Read TX TIME as a 32-bit register to get the 4 lower bytes out of 5
1667
}
1668
1669
/*! ------------------------------------------------------------------------------------------------------------------
1670
 * @fn dwt_readrxtimestamp()
1671
 *
1672
 * @brief This is used to read the RX timestamp (adjusted time of arrival)
1673
 *
1674
 * input parameters
1675
 * @param timestamp - a pointer to a 5-byte buffer which will store the read RX timestamp time
1676
 *
1677
 * output parameters - the timestamp buffer will contain the value after the function call
1678
 *
1679
 * no return value
1680
 */
1681
void dwt_readrxtimestamp(uint8_t * timestamp)
1682
{
1683
    dwt_readfromdevice(RX_TIME_ID, RX_TIME_RX_STAMP_OFFSET, RX_TIME_RX_STAMP_LEN, timestamp) ; // Get the adjusted time of arrival
1684
}
1685
1686
/*! ------------------------------------------------------------------------------------------------------------------
1687
 * @fn dwt_readrxtimestamphi32()
1688
 *
1689
 * @brief This is used to read the high 32-bits of the RX timestamp (adjusted with the programmed antenna delay)
1690
 *
1691
 * input parameters
1692
 *
1693
 * output parameters
1694
 *
1695
 * returns high 32-bits of RX timestamp
1696
 */
1697
uint32_t dwt_readrxtimestamphi32(void)
1698
{
1699
    return dwt_read32bitoffsetreg(RX_TIME_ID, 1); // Offset is 1 to get the 4 upper bytes out of 5
1700
}
1701
1702
/*! ------------------------------------------------------------------------------------------------------------------
1703
 * @fn dwt_readrxtimestamplo32()
1704
 *
1705
 * @brief This is used to read the low 32-bits of the RX timestamp (adjusted with the programmed antenna delay)
1706
 *
1707
 * input parameters
1708
 *
1709
 * output parameters
1710
 *
1711
 * returns low 32-bits of RX timestamp
1712
 */
1713
uint32_t dwt_readrxtimestamplo32(void)
1714
{
1715
    return dwt_read32bitreg(RX_TIME_ID); // Read RX TIME as a 32-bit register to get the 4 lower bytes out of 5
1716
}
1717
1718
/*! ------------------------------------------------------------------------------------------------------------------
1719
 * @fn dwt_readsystimestamphi32()
1720
 *
1721
 * @brief This is used to read the high 32-bits of the system time
1722
 *
1723
 * input parameters
1724
 *
1725
 * output parameters
1726
 *
1727
 * returns high 32-bits of system time timestamp
1728
 */
1729
uint32_t dwt_readsystimestamphi32(void)
1730
{
1731
    return dwt_read32bitoffsetreg(SYS_TIME_ID, 1); // Offset is 1 to get the 4 upper bytes out of 5
1732
}
1733
1734
/*! ------------------------------------------------------------------------------------------------------------------
1735
 * @fn dwt_readsystime()
1736
 *
1737
 * @brief This is used to read the system time
1738
 *
1739
 * input parameters
1740
 * @param timestamp - a pointer to a 5-byte buffer which will store the read system time
1741
 *
1742
 * output parameters
1743
 * @param timestamp - the timestamp buffer will contain the value after the function call
1744
 *
1745
 * no return value
1746
 */
1747
void dwt_readsystime(uint8_t * timestamp)
1748
{
1749
    dwt_readfromdevice(SYS_TIME_ID, SYS_TIME_OFFSET, SYS_TIME_LEN, timestamp) ;
1750
}
1751
1752
/*! ------------------------------------------------------------------------------------------------------------------
1753
 * @fn dwt_writetodevice()
1754
 *
1755
 * @brief  this function is used to write to the DW1000 device registers
1756
 * Notes:
1757
 *        1. Firstly we create a header (the first byte is a header byte)
1758
 *        a. check if sub index is used, if subindexing is used - set bit-6 to 1 to signify that the sub-index address follows the register index byte
1759
 *        b. set bit-7 (or with 0x80) for write operation
1760
 *        c. if extended sub address index is used (i.e. if index > 127) set bit-7 of the first sub-index byte following the first header byte
1761
 *
1762
 *        2. Write the header followed by the data bytes to the DW1000 device
1763
 *
1764
 *
1765
 * input parameters:
1766
 * @param recordNumber  - ID of register file or buffer being accessed
1767
 * @param index         - byte index into register file or buffer being accessed
1768
 * @param length        - number of bytes being written
1769
 * @param buffer        - pointer to buffer containing the 'length' bytes to be written
1770
 *
1771
 * output parameters
1772
 *
1773
 * no return value
1774
 */
1775
void dwt_writetodevice
1776
(
1777
    uint16_t      recordNumber,
1778
    uint16_t      index,
1779
    uint32_t      length,
1780
    const uint8_t *buffer
1781
)
1782
{
1783
    uint8_t header[3] ; // Buffer to compose header in
1784
    int   cnt = 0; // Counter for length of header
1785
#ifdef DWT_API_ERROR_CHECK
1786
    assert(recordNumber <= 0x3F); // Record number is limited to 6-bits.
1787
#endif
1788
1789
    // Write message header selecting WRITE operation and addresses as appropriate (this is one to three bytes long)
1790
    if (index == 0) // For index of 0, no sub-index is required
1791
    {
1792
        header[cnt++] = 0x80 | recordNumber ; // Bit-7 is WRITE operation, bit-6 zero=NO sub-addressing, bits 5-0 is reg file id
1793
    }
1794
    else
1795
    {
1796
#ifdef DWT_API_ERROR_CHECK
1797
        assert((index <= 0x7FFF) && ((index + length) <= 0x7FFF)); // Index and sub-addressable area are limited to 15-bits.
1798
#endif
1799
        header[cnt++] = 0xC0 | recordNumber ; // Bit-7 is WRITE operation, bit-6 one=sub-address follows, bits 5-0 is reg file id
1800
1801
        if (index <= 127) // For non-zero index < 127, just a single sub-index byte is required
1802
        {
1803
            header[cnt++] = (uint8_t)index ; // Bit-7 zero means no extension, bits 6-0 is index.
1804
        }
1805
        else
1806
        {
1807
            header[cnt++] = 0x80 | (uint8_t)(index) ; // Bit-7 one means extended index, bits 6-0 is low seven bits of index.
1808
            header[cnt++] =  (uint8_t) (index >> 7) ; // 8-bit value = high eight bits of index.
1809
        }
1810
    }
1811
1812
    // Write it to the SPI
1813 33f54213 Cung Sang
    writetospi(cnt,header,length,buffer);
1814 69a601a5 Cung Sang
} // end dwt_writetodevice()
1815
1816
/*! ------------------------------------------------------------------------------------------------------------------
1817
 * @fn dwt_readfromdevice()
1818
 *
1819
 * @brief  this function is used to read from the DW1000 device registers
1820
 * Notes:
1821
 *        1. Firstly we create a header (the first byte is a header byte)
1822
 *        a. check if sub index is used, if subindexing is used - set bit-6 to 1 to signify that the sub-index address follows the register index byte
1823
 *        b. set bit-7 (or with 0x80) for write operation
1824
 *        c. if extended sub address index is used (i.e. if index > 127) set bit-7 of the first sub-index byte following the first header byte
1825
 *
1826
 *        2. Write the header followed by the data bytes to the DW1000 device
1827
 *        3. Store the read data in the input buffer
1828
 *
1829
 * input parameters:
1830
 * @param recordNumber  - ID of register file or buffer being accessed
1831
 * @param index         - byte index into register file or buffer being accessed
1832
 * @param length        - number of bytes being read
1833
 * @param buffer        - pointer to buffer in which to return the read data.
1834
 *
1835
 * output parameters
1836
 *
1837
 * no return value
1838
 */
1839
void dwt_readfromdevice
1840
(
1841
    uint16_t  recordNumber,
1842
    uint16_t  index,
1843
    uint32_t  length,
1844
    uint8_t   *buffer
1845
)
1846
{
1847
    uint8_t header[3] ; // Buffer to compose header in
1848
    int   cnt = 0; // Counter for length of header
1849
#ifdef DWT_API_ERROR_CHECK
1850
    assert(recordNumber <= 0x3F); // Record number is limited to 6-bits.
1851
#endif
1852
1853
    // Write message header selecting READ operation and addresses as appropriate (this is one to three bytes long)
1854
    if (index == 0) // For index of 0, no sub-index is required
1855
    {
1856
        header[cnt++] = (uint8_t) recordNumber ; // Bit-7 zero is READ operation, bit-6 zero=NO sub-addressing, bits 5-0 is reg file id
1857
    }
1858
    else
1859
    {
1860
#ifdef DWT_API_ERROR_CHECK
1861
        assert((index <= 0x7FFF) && ((index + length) <= 0x7FFF)); // Index and sub-addressable area are limited to 15-bits.
1862
#endif
1863
        header[cnt++] = (uint8_t)(0x40 | recordNumber) ; // Bit-7 zero is READ operation, bit-6 one=sub-address follows, bits 5-0 is reg file id
1864
1865
        if (index <= 127) // For non-zero index < 127, just a single sub-index byte is required
1866
        {
1867
            header[cnt++] = (uint8_t) index ; // Bit-7 zero means no extension, bits 6-0 is index.
1868
        }
1869
        else
1870
        {
1871
            header[cnt++] = 0x80 | (uint8_t)(index) ; // Bit-7 one means extended index, bits 6-0 is low seven bits of index.
1872
            header[cnt++] =  (uint8_t) (index >> 7) ; // 8-bit value = high eight bits of index.
1873
        }
1874
    }
1875
1876
    // Do the read from the SPI
1877 33f54213 Cung Sang
    readfromspi(cnt, header, length, buffer);
1878 69a601a5 Cung Sang
} // end dwt_readfromdevice()
1879
1880
1881
1882
/*! ------------------------------------------------------------------------------------------------------------------
1883
 * @fn dwt_read32bitoffsetreg()
1884
 *
1885
 * @brief  this function is used to read 32-bit value from the DW1000 device registers
1886
 *
1887
 * input parameters:
1888
 * @param regFileID - ID of register file or buffer being accessed
1889
 * @param regOffset - the index into register file or buffer being accessed
1890
 *
1891
 * output parameters
1892
 *
1893
 * returns 32 bit register value
1894
 */
1895
uint32_t dwt_read32bitoffsetreg(int regFileID,int regOffset)
1896
{
1897
    uint32_t  regval = 0 ;
1898
    int     j ;
1899
    uint8_t   buffer[4] ;
1900
1901
    dwt_readfromdevice(regFileID,regOffset,4,buffer); // Read 4 bytes (32-bits) register into buffer
1902
1903
    for (j = 3 ; j >= 0 ; j --)
1904
    {
1905
        regval = (regval << 8) + buffer[j] ;
1906
    }
1907
    return regval ;
1908
1909
} // end dwt_read32bitoffsetreg()
1910
1911
/*! ------------------------------------------------------------------------------------------------------------------
1912
 * @fn dwt_read16bitoffsetreg()
1913
 *
1914
 * @brief  this function is used to read 16-bit value from the DW1000 device registers
1915
 *
1916
 * input parameters:
1917
 * @param regFileID - ID of register file or buffer being accessed
1918
 * @param regOffset - the index into register file or buffer being accessed
1919
 *
1920
 * output parameters
1921
 *
1922
 * returns 16 bit register value
1923
 */
1924
uint16_t dwt_read16bitoffsetreg(int regFileID,int regOffset)
1925
{
1926
    uint16_t  regval = 0 ;
1927
    uint8_t   buffer[2] ;
1928
1929
    dwt_readfromdevice(regFileID,regOffset,2,buffer); // Read 2 bytes (16-bits) register into buffer
1930
1931
    regval = (buffer[1] << 8) + buffer[0] ;
1932
    return regval ;
1933
1934
} // end dwt_read16bitoffsetreg()
1935
1936
/*! ------------------------------------------------------------------------------------------------------------------
1937
 * @fn dwt_read8bitoffsetreg()
1938
 *
1939
 * @brief  this function is used to read an 8-bit value from the DW1000 device registers
1940
 *
1941
 * input parameters:
1942
 * @param regFileID - ID of register file or buffer being accessed
1943
 * @param regOffset - the index into register file or buffer being accessed
1944
 *
1945
 * output parameters
1946
 *
1947
 * returns 8-bit register value
1948
 */
1949
uint8_t dwt_read8bitoffsetreg(int regFileID, int regOffset)
1950
{
1951
    uint8_t regval;
1952
1953
    dwt_readfromdevice(regFileID, regOffset, 1, &regval);
1954
1955
    return regval ;
1956
}
1957
1958
/*! ------------------------------------------------------------------------------------------------------------------
1959
 * @fn dwt_write8bitoffsetreg()
1960
 *
1961
 * @brief  this function is used to write an 8-bit value to the DW1000 device registers
1962
 *
1963
 * input parameters:
1964
 * @param regFileID - ID of register file or buffer being accessed
1965
 * @param regOffset - the index into register file or buffer being accessed
1966
 * @param regval    - the value to write
1967
 *
1968
 * output parameters
1969
 *
1970
 * no return value
1971
 */
1972
void dwt_write8bitoffsetreg(int regFileID, int regOffset, uint8_t regval)
1973
{
1974
    dwt_writetodevice(regFileID, regOffset, 1, &regval);
1975
}
1976
1977
/*! ------------------------------------------------------------------------------------------------------------------
1978
 * @fn dwt_write16bitoffsetreg()
1979
 *
1980
 * @brief  this function is used to write 16-bit value to the DW1000 device registers
1981
 *
1982
 * input parameters:
1983
 * @param regFileID - ID of register file or buffer being accessed
1984
 * @param regOffset - the index into register file or buffer being accessed
1985
 * @param regval    - the value to write
1986
 *
1987
 * output parameters
1988
 *
1989
 * no return value
1990
 */
1991
void dwt_write16bitoffsetreg(int regFileID,int regOffset,uint16_t regval)
1992
{
1993
    uint8_t   buffer[2] ;
1994
1995
    buffer[0] = regval & 0xFF;
1996
    buffer[1] = regval >> 8 ;
1997
1998
    dwt_writetodevice(regFileID,regOffset,2,buffer);
1999
} // end dwt_write16bitoffsetreg()
2000
2001
/*! ------------------------------------------------------------------------------------------------------------------
2002
 * @fn dwt_write32bitoffsetreg()
2003
 *
2004
 * @brief  this function is used to write 32-bit value to the DW1000 device registers
2005
 *
2006
 * input parameters:
2007
 * @param regFileID - ID of register file or buffer being accessed
2008
 * @param regOffset - the index into register file or buffer being accessed
2009
 * @param regval    - the value to write
2010
 *
2011
 * output parameters
2012
 *
2013
 * no return value
2014
 */
2015
void dwt_write32bitoffsetreg(int regFileID,int regOffset,uint32_t regval)
2016
{
2017
    int     j ;
2018
    uint8_t   buffer[4] ;
2019
2020
    for ( j = 0 ; j < 4 ; j++ )
2021
    {
2022
        buffer[j] = regval & 0xff ;
2023
        regval >>= 8 ;
2024
    }
2025
2026
    dwt_writetodevice(regFileID,regOffset,4,buffer);
2027
} // end dwt_write32bitoffsetreg()
2028
2029
/*! ------------------------------------------------------------------------------------------------------------------
2030
 * @fn dwt_enableframefilter()
2031
 *
2032
 * @brief This is used to enable the frame filtering - (the default option is to
2033
 * accept any data and ACK frames with correct destination address
2034
 *
2035
 * input parameters
2036
 * @param - bitmask - enables/disables the frame filtering options according to
2037
 *      DWT_FF_NOTYPE_EN        0x000   no frame types allowed
2038
 *      DWT_FF_COORD_EN         0x002   behave as coordinator (can receive frames with no destination address (PAN ID has to match))
2039
 *      DWT_FF_BEACON_EN        0x004   beacon frames allowed
2040
 *      DWT_FF_DATA_EN          0x008   data frames allowed
2041
 *      DWT_FF_ACK_EN           0x010   ack frames allowed
2042
 *      DWT_FF_MAC_EN           0x020   mac control frames allowed
2043
 *      DWT_FF_RSVD_EN          0x040   reserved frame types allowed
2044
 *
2045
 * output parameters
2046
 *
2047
 * no return value
2048
 */
2049
void dwt_enableframefilter(uint16_t enable)
2050
{
2051
    uint32_t sysconfig = SYS_CFG_MASK & dwt_read32bitreg(SYS_CFG_ID) ; // Read sysconfig register
2052
2053
    if(enable)
2054
    {
2055
        // Enable frame filtering and configure frame types
2056
        sysconfig &= ~(SYS_CFG_FF_ALL_EN); // Clear all
2057
        sysconfig |= (enable & SYS_CFG_FF_ALL_EN) | SYS_CFG_FFE;
2058
    }
2059
    else
2060
    {
2061
        sysconfig &= ~(SYS_CFG_FFE);
2062
    }
2063
2064
    pdw1000local->sysCFGreg = sysconfig ;
2065
    dwt_write32bitreg(SYS_CFG_ID,sysconfig) ;
2066
}
2067
2068
/*! ------------------------------------------------------------------------------------------------------------------
2069
 * @fn dwt_setpanid()
2070
 *
2071
 * @brief This is used to set the PAN ID
2072
 *
2073
 * input parameters
2074
 * @param panID - this is the PAN ID
2075
 *
2076
 * output parameters
2077
 *
2078
 * no return value
2079
 */
2080
void dwt_setpanid(uint16_t panID)
2081
{
2082
    // PAN ID is high 16 bits of register
2083
    dwt_write16bitoffsetreg(PANADR_ID, PANADR_PAN_ID_OFFSET, panID);
2084
}
2085
2086
/*! ------------------------------------------------------------------------------------------------------------------
2087
 * @fn dwt_setaddress16()
2088
 *
2089
 * @brief This is used to set 16-bit (short) address
2090
 *
2091
 * input parameters
2092
 * @param shortAddress - this sets the 16 bit short address
2093
 *
2094
 * output parameters
2095
 *
2096
 * no return value
2097
 */
2098
void dwt_setaddress16(uint16_t shortAddress)
2099
{
2100
    // Short address into low 16 bits
2101
    dwt_write16bitoffsetreg(PANADR_ID, PANADR_SHORT_ADDR_OFFSET, shortAddress);
2102
}
2103
2104
/*! ------------------------------------------------------------------------------------------------------------------
2105
 * @fn dwt_seteui()
2106
 *
2107
 * @brief This is used to set the EUI 64-bit (long) address
2108
 *
2109
 * input parameters
2110
 * @param eui64 - this is the pointer to a buffer that contains the 64bit address
2111
 *
2112
 * output parameters
2113
 *
2114
 * no return value
2115
 */
2116
void dwt_seteui(uint8_t *eui64)
2117
{
2118
    dwt_writetodevice(EUI_64_ID, EUI_64_OFFSET, EUI_64_LEN, eui64);
2119
}
2120
2121
/*! ------------------------------------------------------------------------------------------------------------------
2122
 * @fn dwt_geteui()
2123
 *
2124
 * @brief This is used to get the EUI 64-bit from the DW1000
2125
 *
2126
 * input parameters
2127
 * @param eui64 - this is the pointer to a buffer that will contain the read 64-bit EUI value
2128
 *
2129
 * output parameters
2130
 *
2131
 * no return value
2132
 */
2133
void dwt_geteui(uint8_t *eui64)
2134
{
2135
    dwt_readfromdevice(EUI_64_ID, EUI_64_OFFSET, EUI_64_LEN, eui64);
2136
}
2137
2138
/*! ------------------------------------------------------------------------------------------------------------------
2139
 * @fn dwt_otpread()
2140
 *
2141
 * @brief This is used to read the OTP data from given address into provided array
2142
 *
2143
 * input parameters
2144
 * @param address - this is the OTP address to read from
2145
 * @param array - this is the pointer to the array into which to read the data
2146
 * @param length - this is the number of 32 bit words to read (array needs to be at least this length)
2147
 *
2148
 * output parameters
2149
 *
2150
 * no return value
2151
 */
2152
void dwt_otpread(uint32_t address, uint32_t *array, uint8_t length)
2153
{
2154
    int i;
2155
2156
    _dwt_enableclocks(FORCE_SYS_XTI); // NOTE: Set system clock to XTAL - this is necessary to make sure the values read by _dwt_otpread are reliable
2157
2158
    for(i=0; i<length; i++)
2159
    {
2160
        array[i] = _dwt_otpread(address + i) ;
2161
    }
2162
2163
    _dwt_enableclocks(ENABLE_ALL_SEQ); // Restore system clock to PLL
2164
2165
    return ;
2166
}
2167
2168
/*! ------------------------------------------------------------------------------------------------------------------
2169
 * @fn _dwt_otpread()
2170
 *
2171
 * @brief function to read the OTP memory. Ensure that MR,MRa,MRb are reset to 0.
2172
 *
2173
 * input parameters
2174
 * @param address - address to read at
2175
 *
2176
 * output parameters
2177
 *
2178
 * returns the 32bit of read data
2179
 */
2180
uint32_t _dwt_otpread(uint32_t address)
2181
{
2182
    uint32_t ret_data;
2183
2184
    // Write the address
2185
    dwt_write16bitoffsetreg(OTP_IF_ID, OTP_ADDR, address);
2186
2187
    // Perform OTP Read - Manual read mode has to be set
2188
    dwt_write8bitoffsetreg(OTP_IF_ID, OTP_CTRL, OTP_CTRL_OTPREAD | OTP_CTRL_OTPRDEN);
2189
    dwt_write8bitoffsetreg(OTP_IF_ID, OTP_CTRL, 0x00); // OTPREAD is self clearing but OTPRDEN is not
2190
2191
    // Read read data, available 40ns after rising edge of OTP_READ
2192
    ret_data = dwt_read32bitoffsetreg(OTP_IF_ID, OTP_RDAT);
2193
2194
    // Return the 32bit of read data
2195
    return ret_data;
2196
}
2197
2198
/*! ------------------------------------------------------------------------------------------------------------------
2199
 * @fn _dwt_otpsetmrregs()
2200
 *
2201
 * @brief Configure the MR registers for initial programming (enable charge pump).
2202
 * Read margin is used to stress the read back from the
2203
 * programmed bit. In normal operation this is relaxed.
2204
 *
2205
 * input parameters
2206
 * @param mode - "0" : Reset all to 0x0:           MRA=0x0000, MRB=0x0000, MR=0x0000
2207
 *               "1" : Set for inital programming: MRA=0x9220, MRB=0x000E, MR=0x1024
2208
 *               "2" : Set for soak programming:   MRA=0x9220, MRB=0x0003, MR=0x1824
2209
 *               "3" : High Vpp:                   MRA=0x9220, MRB=0x004E, MR=0x1824
2210
 *               "4" : Low Read Margin:            MRA=0x0000, MRB=0x0003, MR=0x0000
2211
 *               "5" : Array Clean:                MRA=0x0049, MRB=0x0003, MR=0x0024
2212
 *               "4" : Very Low Read Margin:       MRA=0x0000, MRB=0x0003, MR=0x0000
2213
 *
2214
 * output parameters
2215
 *
2216
 * returns DWT_SUCCESS for success, or DWT_ERROR for error
2217
 */
2218
uint32_t _dwt_otpsetmrregs(int mode)
2219
{
2220
    uint8_t rd_buf[4];
2221
    uint8_t wr_buf[4];
2222
    uint32_t mra=0,mrb=0,mr=0;
2223
2224
    // PROGRAMME MRA
2225
    // Set MRA, MODE_SEL
2226
    wr_buf[0] = 0x03;
2227
    dwt_writetodevice(OTP_IF_ID, OTP_CTRL+1,1,wr_buf);
2228
2229
    // Load data
2230
    switch(mode&0x0f) {
2231
    case 0x0 :
2232
        mr =0x0000;
2233
        mra=0x0000;
2234
        mrb=0x0000;
2235
        break;
2236
    case 0x1 :
2237
        mr =0x1024;
2238
        mra=0x9220; // Enable CPP mon
2239
        mrb=0x000e;
2240
        break;
2241
    case 0x2 :
2242
        mr =0x1824;
2243
        mra=0x9220;
2244
        mrb=0x0003;
2245
        break;
2246
    case 0x3 :
2247
        mr =0x1824;
2248
        mra=0x9220;
2249
        mrb=0x004e;
2250
        break;
2251
    case 0x4 :
2252
        mr =0x0000;
2253
        mra=0x0000;
2254
        mrb=0x0003;
2255
        break;
2256
    case 0x5 :
2257
        mr =0x0024;
2258
        mra=0x0000;
2259
        mrb=0x0003;
2260
        break;
2261
    default :
2262
        return DWT_ERROR;
2263
    }
2264
2265
    wr_buf[0] = mra & 0x00ff;
2266
    wr_buf[1] = (mra & 0xff00)>>8;
2267
    dwt_writetodevice(OTP_IF_ID, OTP_WDAT,2,wr_buf);
2268
2269
2270
    // Set WRITE_MR
2271
    wr_buf[0] = 0x08;
2272
    dwt_writetodevice(OTP_IF_ID, OTP_CTRL,1,wr_buf);
2273
2274
    // Wait?
2275
2276
    // Set Clear Mode sel
2277
    wr_buf[0] = 0x02;
2278
    dwt_writetodevice(OTP_IF_ID,OTP_CTRL+1,1,wr_buf);
2279
2280
    // Set AUX update, write MR
2281
    wr_buf[0] = 0x88;
2282
    dwt_writetodevice(OTP_IF_ID, OTP_CTRL,1,wr_buf);
2283
    // Clear write MR
2284
    wr_buf[0] = 0x80;
2285
    dwt_writetodevice(OTP_IF_ID, OTP_CTRL,1,wr_buf);
2286
    // Clear AUX update
2287
    wr_buf[0] = 0x00;
2288
    dwt_writetodevice(OTP_IF_ID, OTP_CTRL,1,wr_buf);
2289
2290
    ///////////////////////////////////////////
2291
    // PROGRAM MRB
2292
    // Set SLOW, MRB, MODE_SEL
2293
    wr_buf[0] = 0x05;
2294
    dwt_writetodevice(OTP_IF_ID,OTP_CTRL+1,1,wr_buf);
2295
2296
    wr_buf[0] = mrb & 0x00ff;
2297
    wr_buf[1] = (mrb & 0xff00)>>8;
2298
    dwt_writetodevice(OTP_IF_ID, OTP_WDAT,2,wr_buf);
2299
2300
    // Set WRITE_MR
2301
    wr_buf[0] = 0x08;
2302
    dwt_writetodevice(OTP_IF_ID, OTP_CTRL,1,wr_buf);
2303
2304
    // Wait?
2305
2306
    // Set Clear Mode sel
2307
    wr_buf[0] = 0x04;
2308
    dwt_writetodevice(OTP_IF_ID,OTP_CTRL+1,1,wr_buf);
2309
2310
    // Set AUX update, write MR
2311
    wr_buf[0] = 0x88;
2312
    dwt_writetodevice(OTP_IF_ID, OTP_CTRL,1,wr_buf);
2313
    // Clear write MR
2314
    wr_buf[0] = 0x80;
2315
    dwt_writetodevice(OTP_IF_ID, OTP_CTRL,1,wr_buf);
2316
    // Clear AUX update
2317
    wr_buf[0] = 0x00;
2318
    dwt_writetodevice(OTP_IF_ID, OTP_CTRL,1,wr_buf);
2319
2320
    ///////////////////////////////////////////
2321
    // PROGRAM MR
2322
    // Set SLOW, MODE_SEL
2323
    wr_buf[0] = 0x01;
2324
    dwt_writetodevice(OTP_IF_ID,OTP_CTRL+1,1,wr_buf);
2325
    // Load data
2326
2327
    wr_buf[0] = mr & 0x00ff;
2328
    wr_buf[1] = (mr & 0xff00)>>8;
2329
    dwt_writetodevice(OTP_IF_ID, OTP_WDAT,2,wr_buf);
2330
2331
    // Set WRITE_MR
2332
    wr_buf[0] = 0x08;
2333
    dwt_writetodevice(OTP_IF_ID, OTP_CTRL,1,wr_buf);
2334
2335
    // Wait?
2336
    deca_sleep(10);
2337
    // Set Clear Mode sel
2338
    wr_buf[0] = 0x00;
2339
    dwt_writetodevice(OTP_IF_ID,OTP_CTRL+1,1,wr_buf);
2340
2341
    // Read confirm mode writes.
2342
    // Set man override, MRA_SEL
2343
    wr_buf[0] = OTP_CTRL_OTPRDEN;
2344
    dwt_writetodevice(OTP_IF_ID, OTP_CTRL,1,wr_buf);
2345
    wr_buf[0] = 0x02;
2346
    dwt_writetodevice(OTP_IF_ID,OTP_CTRL+1,1,wr_buf);
2347
    // MRB_SEL
2348
    wr_buf[0] = 0x04;
2349
    dwt_writetodevice(OTP_IF_ID,OTP_CTRL+1,1,wr_buf);
2350
    deca_sleep(100);
2351
2352
    // Clear mode sel
2353
    wr_buf[0] = 0x00;
2354
    dwt_writetodevice(OTP_IF_ID,OTP_CTRL+1,1,wr_buf);
2355
    // Clear MAN_OVERRIDE
2356
    wr_buf[0] = 0x00;
2357
    dwt_writetodevice(OTP_IF_ID, OTP_CTRL,1,wr_buf);
2358
2359
    deca_sleep(10);
2360
2361
    if (((mode&0x0f) == 0x1)||((mode&0x0f) == 0x2))
2362
    {
2363
        // Read status register
2364
        dwt_readfromdevice(OTP_IF_ID, OTP_STAT,1,rd_buf);
2365
    }
2366
2367
    return DWT_SUCCESS;
2368
}
2369
2370
/*! ------------------------------------------------------------------------------------------------------------------
2371
 * @fn _dwt_otpprogword32()
2372
 *
2373
 * @brief function to program the OTP memory. Ensure that MR,MRa,MRb are reset to 0.
2374
 * VNM Charge pump needs to be enabled (see _dwt_otpsetmrregs)
2375
 * Note the address is only 11 bits long.
2376
 *
2377
 * input parameters
2378
 * @param address - address to read at
2379
 *
2380
 * output parameters
2381
 *
2382
 * returns DWT_SUCCESS for success, or DWT_ERROR for error
2383
 */
2384
uint32_t _dwt_otpprogword32(uint32_t data, uint16_t address)
2385
{
2386
    uint8_t rd_buf[1];
2387
    uint8_t wr_buf[4];
2388
    uint8_t otp_done;
2389
2390
    // Read status register
2391
    dwt_readfromdevice(OTP_IF_ID, OTP_STAT, 1, rd_buf);
2392
2393
    if((rd_buf[0] & 0x02) != 0x02)
2394
    {
2395
        return DWT_ERROR;
2396
    }
2397
2398
    // Write the data
2399
    wr_buf[3] = (data>>24) & 0xff;
2400
    wr_buf[2] = (data>>16) & 0xff;
2401
    wr_buf[1] = (data>>8) & 0xff;
2402
    wr_buf[0] = data & 0xff;
2403
    dwt_writetodevice(OTP_IF_ID, OTP_WDAT, 4, wr_buf);
2404
2405
    // Write the address [10:0]
2406
    wr_buf[1] = (address>>8) & 0x07;
2407
    wr_buf[0] = address & 0xff;
2408
    dwt_writetodevice(OTP_IF_ID, OTP_ADDR, 2, wr_buf);
2409
2410
    // Enable Sequenced programming
2411
    wr_buf[0] = OTP_CTRL_OTPPROG;
2412
    dwt_writetodevice(OTP_IF_ID, OTP_CTRL, 1, wr_buf);
2413
    wr_buf[0] = 0x00; // And clear
2414
    dwt_writetodevice(OTP_IF_ID, OTP_CTRL, 1, wr_buf);
2415
2416
    // WAIT for status to flag PRGM OK..
2417
    otp_done = 0;
2418
    while(otp_done == 0)
2419
    {
2420
        deca_sleep(1);
2421
        dwt_readfromdevice(OTP_IF_ID, OTP_STAT, 1, rd_buf);
2422
2423
        if((rd_buf[0] & 0x01) == 0x01)
2424
        {
2425
            otp_done = 1;
2426
        }
2427
    }
2428
2429
    return DWT_SUCCESS;
2430
}
2431
2432
/*! ------------------------------------------------------------------------------------------------------------------
2433
 * @fn dwt_otpwriteandverify()
2434
 *
2435
 * @brief This is used to program 32-bit value into the DW1000 OTP memory.
2436
 *
2437
 * input parameters
2438
 * @param value - this is the 32-bit value to be programmed into OTP
2439
 * @param address - this is the 16-bit OTP address into which the 32-bit value is programmed
2440
 *
2441
 * output parameters
2442
 *
2443
 * returns DWT_SUCCESS for success, or DWT_ERROR for error
2444
 */
2445
int dwt_otpwriteandverify(uint32_t value, uint16_t address)
2446
{
2447
    int prog_ok = DWT_SUCCESS;
2448
    int retry = 0;
2449
    // Firstly set the system clock to crystal
2450
    _dwt_enableclocks(FORCE_SYS_XTI); //set system clock to XTI
2451
2452
    //
2453
    //!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!
2454
    //Set the supply to 3.7V
2455
    //
2456
2457
    _dwt_otpsetmrregs(1); // Set mode for programming
2458
2459
    // For each value to program - the readback/check is done couple of times to verify it has programmed successfully
2460
    while(1)
2461
    {
2462
        _dwt_otpprogword32(value, address);
2463
2464
        if(_dwt_otpread(address) == value)
2465
        {
2466
            break;
2467
        }
2468
        retry++;
2469
        if(retry==5)
2470
        {
2471
            break;
2472
        }
2473
    }
2474
2475
    // Even if the above does not exit before retry reaches 5, the programming has probably been successful
2476
2477
    _dwt_otpsetmrregs(4); // Set mode for reading
2478
2479
    if(_dwt_otpread(address) != value) // If this does not pass please check voltage supply on VDDIO
2480
    {
2481
        prog_ok = DWT_ERROR;
2482
    }
2483
2484
    _dwt_otpsetmrregs(0); // Setting OTP mode register for low RM read - resetting the device would be alternative
2485
2486
    return prog_ok;
2487
}
2488
2489
/*! ------------------------------------------------------------------------------------------------------------------
2490
 * @fn _dwt_aonconfigupload()
2491
 *
2492
 * @brief This function uploads always on (AON) configuration, as set in the AON_CFG0_OFFSET register.
2493
 *
2494
 * input parameters
2495
 *
2496
 * output parameters
2497
 *
2498
 * no return value
2499
 */
2500
void _dwt_aonconfigupload(void)
2501
{
2502
    dwt_write8bitoffsetreg(AON_ID, AON_CTRL_OFFSET, AON_CTRL_UPL_CFG);
2503
    dwt_write8bitoffsetreg(AON_ID, AON_CTRL_OFFSET, 0x00); // Clear the register
2504
}
2505
2506
/*! ------------------------------------------------------------------------------------------------------------------
2507
 * @fn _dwt_aonarrayupload()
2508
 *
2509
 * @brief This function uploads always on (AON) data array and configuration. Thus if this function is used, then _dwt_aonconfigupload
2510
 * is not necessary. The DW1000 will go so SLEEP straight after this if the DWT_SLP_EN has been set.
2511
 *
2512
 * input parameters
2513
 *
2514
 * output parameters
2515
 *
2516
 * no return value
2517
 */
2518
void _dwt_aonarrayupload(void)
2519
{
2520
    dwt_write8bitoffsetreg(AON_ID, AON_CTRL_OFFSET, 0x00); // Clear the register
2521
    dwt_write8bitoffsetreg(AON_ID, AON_CTRL_OFFSET, AON_CTRL_SAVE);
2522
}
2523
2524
/*! ------------------------------------------------------------------------------------------------------------------
2525
 * @fn dwt_entersleep()
2526
 *
2527
 * @brief This function puts the device into deep sleep or sleep. dwt_configuresleep() should be called first
2528
 * to configure the sleep and on-wake/wake-up parameters
2529
 *
2530
 * input parameters
2531
 *
2532
 * output parameters
2533
 *
2534
 * no return value
2535
 */
2536
void dwt_entersleep(void)
2537
{
2538
    // Copy config to AON - upload the new configuration
2539
    _dwt_aonarrayupload();
2540
}
2541
2542
/*! ------------------------------------------------------------------------------------------------------------------
2543
 * @fn dwt_configuresleepcnt()
2544
 *
2545
 * @brief sets the sleep counter to new value, this function programs the high 16-bits of the 28-bit counter
2546
 *
2547
 * NOTE: this function needs to be run before dwt_configuresleep, also the SPI frequency has to be < 3MHz
2548
 *
2549
 * input parameters
2550
 * @param sleepcnt - this it value of the sleep counter to program
2551
 *
2552
 * output parameters
2553
 *
2554
 * no return value
2555
 */
2556
void dwt_configuresleepcnt(uint16_t sleepcnt)
2557
{
2558
    // Force system clock to crystal
2559
    _dwt_enableclocks(FORCE_SYS_XTI);
2560
2561
    // Reset sleep configuration to make sure we don't accidentally go to sleep
2562
    dwt_write8bitoffsetreg(AON_ID, AON_CFG0_OFFSET, 0x00); // NB: this write change the default LPCLKDIVA value which is not used anyway.
2563
    dwt_write8bitoffsetreg(AON_ID, AON_CFG1_OFFSET, 0x00);
2564
2565
    // Disable the sleep counter
2566
    _dwt_aonconfigupload();
2567
2568
    // Set new value
2569
    dwt_write16bitoffsetreg(AON_ID, AON_CFG0_OFFSET + AON_CFG0_SLEEP_TIM_OFFSET, sleepcnt);
2570
    _dwt_aonconfigupload();
2571
2572
    // Enable the sleep counter
2573
    dwt_write8bitoffsetreg(AON_ID, AON_CFG1_OFFSET, AON_CFG1_SLEEP_CEN);
2574
    _dwt_aonconfigupload();
2575
2576
    // Put system PLL back on
2577
    _dwt_enableclocks(ENABLE_ALL_SEQ);
2578
}
2579
2580
2581
/*! ------------------------------------------------------------------------------------------------------------------
2582
 * @fn dwt_calibratesleepcnt()
2583
 *
2584
 * @brief calibrates the local oscillator as its frequency can vary between 7 and 13kHz depending on temp and voltage
2585
 *
2586
 * NOTE: this function needs to be run before dwt_configuresleepcnt, so that we know what the counter units are
2587
 *
2588
 * input parameters
2589
 *
2590
 * output parameters
2591
 *
2592
 * returns the number of XTAL/2 cycles per low-power oscillator cycle. LP OSC frequency = 19.2 MHz/return value
2593
 */
2594
uint16_t dwt_calibratesleepcnt(void)
2595
{
2596
    uint16_t result;
2597
2598
    // Enable calibration of the sleep counter
2599
    dwt_write8bitoffsetreg(AON_ID, AON_CFG1_OFFSET, AON_CFG1_LPOSC_CAL);
2600
    _dwt_aonconfigupload();
2601
2602
    // Disable calibration of the sleep counter
2603
    dwt_write8bitoffsetreg(AON_ID, AON_CFG1_OFFSET, 0x00);
2604
    _dwt_aonconfigupload();
2605
2606
    // Force system clock to crystal
2607
    _dwt_enableclocks(FORCE_SYS_XTI);
2608
2609
    deca_sleep(1);
2610
2611
    // Read the number of XTAL/2 cycles one LP oscillator cycle took.
2612
    // Set up address - Read upper byte first
2613
    dwt_write8bitoffsetreg(AON_ID, AON_ADDR_OFFSET, AON_ADDR_LPOSC_CAL_1);
2614
2615
    // Enable manual override
2616
    dwt_write8bitoffsetreg(AON_ID, AON_CTRL_OFFSET, AON_CTRL_DCA_ENAB);
2617
2618
    // Read confirm data that was written
2619
    dwt_write8bitoffsetreg(AON_ID, AON_CTRL_OFFSET, AON_CTRL_DCA_ENAB | AON_CTRL_DCA_READ);
2620
2621
    // Read back byte from AON
2622
    result = dwt_read8bitoffsetreg(AON_ID, AON_RDAT_OFFSET);
2623
    result <<= 8;
2624
2625
    // Set up address - Read lower byte
2626
    dwt_write8bitoffsetreg(AON_ID, AON_ADDR_OFFSET, AON_ADDR_LPOSC_CAL_0);
2627
2628
    // Enable manual override
2629
    dwt_write8bitoffsetreg(AON_ID, AON_CTRL_OFFSET, AON_CTRL_DCA_ENAB);
2630
2631
    // Read confirm data that was written
2632
    dwt_write8bitoffsetreg(AON_ID, AON_CTRL_OFFSET, AON_CTRL_DCA_ENAB | AON_CTRL_DCA_READ);
2633
2634
    // Read back byte from AON
2635
    result |= dwt_read8bitoffsetreg(AON_ID, AON_RDAT_OFFSET);
2636
2637
    // Disable manual override
2638
    dwt_write8bitoffsetreg(AON_ID, AON_CTRL_OFFSET, 0x00);
2639
2640
    // Put system PLL back on
2641
    _dwt_enableclocks(ENABLE_ALL_SEQ);
2642
2643
    // Returns the number of XTAL/2 cycles per one LP OSC cycle
2644
    // This can be converted into LP OSC frequency by 19.2 MHz/result
2645
    return result;
2646
}
2647
2648
/*! ------------------------------------------------------------------------------------------------------------------
2649
 * @fn dwt_configuresleep()
2650
 *
2651
 * @brief configures the device for both DEEP_SLEEP and SLEEP modes, and on-wake mode
2652
 * i.e. before entering the sleep, the device should be programmed for TX or RX, then upon "waking up" the TX/RX settings
2653
 * will be preserved and the device can immediately perform the desired action TX/RX
2654
 *
2655
 * NOTE: e.g. Tag operation - after deep sleep, the device needs to just load the TX buffer and send the frame
2656
 *
2657
 *
2658
 *      mode: the array and LDE code (OTP/ROM) and LDO tune, and set sleep persist
2659
 *      DWT_PRESRV_SLEEP 0x0100 - preserve sleep
2660
 *      DWT_LOADOPSET    0x0080 - load operating parameter set on wakeup
2661
 *      DWT_CONFIG       0x0040 - download the AON array into the HIF (configuration download)
2662
 *      DWT_LOADEUI      0x0008
2663
 *      DWT_GOTORX       0x0002
2664
 *      DWT_TANDV        0x0001
2665
 *
2666
 *      wake: wake up parameters
2667
 *      DWT_XTAL_EN      0x10 - keep XTAL running during sleep
2668
 *      DWT_WAKE_SLPCNT  0x8 - wake up after sleep count
2669
 *      DWT_WAKE_CS      0x4 - wake up on chip select
2670
 *      DWT_WAKE_WK      0x2 - wake up on WAKEUP PIN
2671
 *      DWT_SLP_EN       0x1 - enable sleep/deep sleep functionality
2672
 *
2673
 * input parameters
2674
 * @param mode - config on-wake parameters
2675
 * @param wake - config wake up parameters
2676
 *
2677
 * output parameters
2678
 *
2679
 * no return value
2680
 */
2681
void dwt_configuresleep(uint16_t mode, uint8_t wake)
2682
{
2683
    // Add predefined sleep settings before writing the mode
2684
    mode |= pdw1000local->sleep_mode;
2685
    dwt_write16bitoffsetreg(AON_ID, AON_WCFG_OFFSET, mode);
2686
2687
    dwt_write8bitoffsetreg(AON_ID, AON_CFG0_OFFSET, wake);
2688
}
2689
2690
/*! ------------------------------------------------------------------------------------------------------------------
2691
 * @fn dwt_entersleepaftertx(int enable)
2692
 *
2693
 * @brief sets the auto TX to sleep bit. This means that after a frame
2694
 * transmission the device will enter deep sleep mode. The dwt_configuresleep() function
2695
 * needs to be called before this to configure the on-wake settings
2696
 *
2697
 * NOTE: the IRQ line has to be low/inactive (i.e. no pending events)
2698
 *
2699
 * input parameters
2700
 * @param enable - 1 to configure the device to enter deep sleep after TX, 0 - disables the configuration
2701
 *
2702
 * output parameters
2703
 *
2704
 * no return value
2705
 */
2706
void dwt_entersleepaftertx(int enable)
2707
{
2708
    uint32_t reg = dwt_read32bitoffsetreg(PMSC_ID, PMSC_CTRL1_OFFSET);
2709
    // Set the auto TX -> sleep bit
2710
    if(enable)
2711
    {
2712
        reg |= PMSC_CTRL1_ATXSLP;
2713
    }
2714
    else
2715
    {
2716
        reg &= ~(PMSC_CTRL1_ATXSLP);
2717
    }
2718
    dwt_write32bitoffsetreg(PMSC_ID, PMSC_CTRL1_OFFSET, reg);
2719
}
2720
2721
2722
/*! ------------------------------------------------------------------------------------------------------------------
2723
 * @fn dwt_spicswakeup()
2724
 *
2725
 * @brief wake up the device from sleep mode using the SPI read,
2726
 * the device will wake up on chip select line going low if the line is held low for at least 500us.
2727
 * To define the length depending on the time one wants to hold
2728
 * the chip select line low, use the following formula:
2729
 *
2730
 *      length (bytes) = time (s) * byte_rate (Hz)
2731
 *
2732
 * where fastest byte_rate is spi_rate (Hz) / 8 if the SPI is sending the bytes back-to-back.
2733
 * To save time and power, a system designer could determine byte_rate value more precisely.
2734
 *
2735
 * NOTE: Alternatively the device can be waken up with WAKE_UP pin if configured for that operation
2736
 *
2737
 * input parameters
2738
 * @param buff   - this is a pointer to the dummy buffer which will be used in the SPI read transaction used for the WAKE UP of the device
2739
 * @param length - this is the length of the dummy buffer
2740
 *
2741
 * output parameters
2742
 *
2743
 * returns DWT_SUCCESS for success, or DWT_ERROR for error
2744
 */
2745
int dwt_spicswakeup(uint8_t *buff, uint16_t length)
2746
{
2747
    if(dwt_readdevid() != DWT_DEVICE_ID) // Device was in deep sleep (the first read fails)
2748
    {
2749
        // Need to keep chip select line low for at least 500us
2750
        dwt_readfromdevice(0x0, 0x0, length, buff); // Do a long read to wake up the chip (hold the chip select low)
2751
2752
        // Need 5ms for XTAL to start and stabilise (could wait for PLL lock IRQ status bit !!!)
2753
        // NOTE: Polling of the STATUS register is not possible unless frequency is < 3MHz
2754
        deca_sleep(5);
2755
    }
2756
    else
2757
    {
2758
        return DWT_SUCCESS;
2759
    }
2760
    // DEBUG - check if still in sleep mode
2761
    if(dwt_readdevid() != DWT_DEVICE_ID)
2762
    {
2763
        return DWT_ERROR;
2764
    }
2765
2766
    return DWT_SUCCESS;
2767
}
2768
2769
/*! ------------------------------------------------------------------------------------------------------------------
2770
 * @fn _dwt_configlde()
2771
 *
2772
 * @brief configure LDE algorithm parameters
2773
 *
2774
 * input parameters
2775
 * @param prf   -   this is the PRF index (0 or 1) 0 corresponds to 16 and 1 to 64 PRF
2776
 *
2777
 * output parameters
2778
 *
2779
 * no return value
2780
 */
2781
void _dwt_configlde(int prfIndex)
2782
{
2783
    dwt_write8bitoffsetreg(LDE_IF_ID, LDE_CFG1_OFFSET, LDE_PARAM1); // 8-bit configuration register
2784
2785
    if(prfIndex)
2786
    {
2787
        dwt_write16bitoffsetreg( LDE_IF_ID, LDE_CFG2_OFFSET, (uint16_t) LDE_PARAM3_64); // 16-bit LDE configuration tuning register
2788
    }
2789
    else
2790
    {
2791
        dwt_write16bitoffsetreg( LDE_IF_ID, LDE_CFG2_OFFSET, (uint16_t) LDE_PARAM3_16);
2792
    }
2793
}
2794
2795
2796
/*! ------------------------------------------------------------------------------------------------------------------
2797
 * @fn _dwt_loaducodefromrom()
2798
 *
2799
 * @brief  load ucode from OTP MEMORY or ROM
2800
 *
2801
 * input parameters
2802
 *
2803
 * output parameters
2804
 *
2805
 * no return value
2806
 */
2807
void _dwt_loaducodefromrom(void)
2808
{
2809
    // Set up clocks
2810
    _dwt_enableclocks(FORCE_LDE);
2811
2812
    // Kick off the LDE load
2813
    dwt_write16bitoffsetreg(OTP_IF_ID, OTP_CTRL, OTP_CTRL_LDELOAD); // Set load LDE kick bit
2814
2815
    deca_sleep(1); // Allow time for code to upload (should take up to 120 us)
2816
2817
    // Default clocks (ENABLE_ALL_SEQ)
2818
    _dwt_enableclocks(ENABLE_ALL_SEQ); // Enable clocks for sequencing
2819
}
2820
2821
/*! ------------------------------------------------------------------------------------------------------------------
2822
 * @fn dwt_loadopsettabfromotp()
2823
 *
2824
 * @brief This is used to select which Operational Parameter Set table to load from OTP memory
2825
 *
2826
 * input parameters
2827
 * @param ops_sel - Operational Parameter Set table to load:
2828
 *                  DWT_OPSET_64LEN = 0x0 - load the operational parameter set table for 64 length preamble configuration
2829
 *                  DWT_OPSET_TIGHT = 0x1 - load the operational parameter set table for tight xtal offsets (<1ppm)
2830
 *                  DWT_OPSET_DEFLT = 0x2 - load the default operational parameter set table (this is loaded from reset)
2831
 *
2832
 * output parameters
2833
 *
2834
 * no return value
2835
 */
2836
void dwt_loadopsettabfromotp(uint8_t ops_sel)
2837
{
2838
    uint16_t reg = ((ops_sel << OTP_SF_OPS_SEL_SHFT) & OTP_SF_OPS_SEL_MASK) | OTP_SF_OPS_KICK; // Select defined OPS table and trigger its loading
2839
2840
    // Set up clocks
2841
    _dwt_enableclocks(FORCE_LDE);
2842
2843
    dwt_write16bitoffsetreg(OTP_IF_ID, OTP_SF, reg);
2844
2845
    // Default clocks (ENABLE_ALL_SEQ)
2846
    _dwt_enableclocks(ENABLE_ALL_SEQ); // Enable clocks for sequencing
2847
2848
}
2849
2850
/*! ------------------------------------------------------------------------------------------------------------------
2851
 * @fn dwt_setsmarttxpower()
2852
 *
2853
 * @brief This call enables or disables the smart TX power feature.
2854
 *
2855
 * input parameters
2856
 * @param enable - this enables or disables the TX smart power (1 = enable, 0 = disable)
2857
 *
2858
 * output parameters
2859
 *
2860
 * no return value
2861
 */
2862
void dwt_setsmarttxpower(int enable)
2863
{
2864
    // Config system register
2865
    pdw1000local->sysCFGreg = dwt_read32bitreg(SYS_CFG_ID) ; // Read sysconfig register
2866
2867
    // Disable smart power configuration
2868
    if(enable)
2869
    {
2870
        pdw1000local->sysCFGreg &= ~(SYS_CFG_DIS_STXP) ;
2871
    }
2872
    else
2873
    {
2874
        pdw1000local->sysCFGreg |= SYS_CFG_DIS_STXP ;
2875
    }
2876
2877
    dwt_write32bitreg(SYS_CFG_ID,pdw1000local->sysCFGreg) ;
2878
}
2879
2880
2881
/*! ------------------------------------------------------------------------------------------------------------------
2882
 * @fn dwt_enableautoack()
2883
 *
2884
 * @brief This call enables the auto-ACK feature. If the responseDelayTime (parameter) is 0, the ACK will be sent a.s.a.p.
2885
 * otherwise it will be sent with a programmed delay (in symbols), max is 255.
2886
 * NOTE: needs to have frame filtering enabled as well
2887
 *
2888
 * input parameters
2889
 * @param responseDelayTime - if non-zero the ACK is sent after this delay, max is 255.
2890
 *
2891
 * output parameters
2892
 *
2893
 * no return value
2894
 */
2895
void dwt_enableautoack(uint8_t responseDelayTime)
2896
{
2897
    // Set auto ACK reply delay
2898
    dwt_write8bitoffsetreg(ACK_RESP_T_ID, ACK_RESP_T_ACK_TIM_OFFSET, responseDelayTime); // In symbols
2899
    // Enable auto ACK
2900
    pdw1000local->sysCFGreg |= SYS_CFG_AUTOACK;
2901
    dwt_write32bitreg(SYS_CFG_ID,pdw1000local->sysCFGreg) ;
2902
}
2903
2904
/*! ------------------------------------------------------------------------------------------------------------------
2905
 * @fn dwt_setdblrxbuffmode()
2906
 *
2907
 * @brief This call enables the double receive buffer mode
2908
 *
2909
 * input parameters
2910
 * @param enable - 1 to enable, 0 to disable the double buffer mode
2911
 *
2912
 * output parameters
2913
 *
2914
 * no return value
2915
 */
2916
void dwt_setdblrxbuffmode(int enable)
2917
{
2918
    if(enable)
2919
    {
2920
        // Enable double RX buffer mode
2921
        pdw1000local->sysCFGreg &= ~SYS_CFG_DIS_DRXB;
2922
        pdw1000local->dblbuffon = 1;
2923
    }
2924
    else
2925
    {
2926
        // Disable double RX buffer mode
2927
        pdw1000local->sysCFGreg |= SYS_CFG_DIS_DRXB;
2928
        pdw1000local->dblbuffon = 0;
2929
    }
2930
2931
    dwt_write32bitreg(SYS_CFG_ID,pdw1000local->sysCFGreg) ;
2932
}
2933
2934
/*! ------------------------------------------------------------------------------------------------------------------
2935
 * @fn dwt_setrxaftertxdelay()
2936
 *
2937
 * @brief This sets the receiver turn on delay time after a transmission of a frame
2938
 *
2939
 * input parameters
2940
 * @param rxDelayTime - (20 bits) - the delay is in UWB microseconds
2941
 *
2942
 * output parameters
2943
 *
2944
 * no return value
2945
 */
2946
void dwt_setrxaftertxdelay(uint32_t rxDelayTime)
2947
{
2948
    uint32_t val = dwt_read32bitreg(ACK_RESP_T_ID) ; // Read ACK_RESP_T_ID register
2949
2950
    val &= ~(ACK_RESP_T_W4R_TIM_MASK) ; // Clear the timer (19:0)
2951
2952
    val |= (rxDelayTime & ACK_RESP_T_W4R_TIM_MASK) ; // In UWB microseconds (e.g. turn the receiver on 20uus after TX)
2953
2954
    dwt_write32bitreg(ACK_RESP_T_ID, val) ;
2955
}
2956
2957
/*! ------------------------------------------------------------------------------------------------------------------
2958
 * @fn dwt_setcallbacks()
2959
 *
2960
 * @brief This function is used to register the different callbacks called when one of the corresponding event occurs.
2961
 *
2962
 * NOTE: Callbacks can be undefined (set to NULL). In this case, dwt_isr() will process the event as usual but the 'null'
2963
 * callback will not be called.
2964
 *
2965
 * input parameters
2966
 * @param cbTxDone - the pointer to the TX confirmation event callback function
2967
 * @param cbRxOk - the pointer to the RX good frame event callback function
2968
 * @param cbRxTo - the pointer to the RX timeout events callback function
2969
 * @param cbRxErr - the pointer to the RX error events callback function
2970
 *
2971
 * output parameters
2972
 *
2973
 * no return value
2974
 */
2975
void dwt_setcallbacks(dwt_cb_t cbTxDone, dwt_cb_t cbRxOk, dwt_cb_t cbRxTo, dwt_cb_t cbRxErr)
2976
{
2977
    pdw1000local->cbTxDone = cbTxDone;
2978
    pdw1000local->cbRxOk = cbRxOk;
2979
    pdw1000local->cbRxTo = cbRxTo;
2980
    pdw1000local->cbRxErr = cbRxErr;
2981
}
2982
2983
/*! ------------------------------------------------------------------------------------------------------------------
2984
 * @fn dwt_checkirq()
2985
 *
2986
 * @brief This function checks if the IRQ line is active - this is used instead of interrupt handler
2987
 *
2988
 * input parameters
2989
 *
2990
 * output parameters
2991
 *
2992
 * return value is 1 if the IRQS bit is set and 0 otherwise
2993
 */
2994
uint8_t dwt_checkirq(void)
2995
{
2996
    return (dwt_read8bitoffsetreg(SYS_STATUS_ID, SYS_STATUS_OFFSET) & SYS_STATUS_IRQS); // Reading the lower byte only is enough for this operation
2997
}
2998
2999
/*! ------------------------------------------------------------------------------------------------------------------
3000
 * @fn dwt_isr()
3001
 *
3002
 * @brief This is the DW1000's general Interrupt Service Routine. It will process/report the following events:
3003
 *          - RXFCG (through cbRxOk callback)
3004
 *          - TXFRS (through cbTxDone callback)
3005
 *          - RXRFTO/RXPTO (through cbRxTo callback)
3006
 *          - RXPHE/RXFCE/RXRFSL/RXSFDTO/AFFREJ/LDEERR (through cbRxTo cbRxErr)
3007
 *        For all events, corresponding interrupts are cleared and necessary resets are performed. In addition, in the RXFCG case,
3008
 *        received frame information and frame control are read before calling the callback. If double buffering is activated, it
3009
 *        will also toggle between reception buffers once the reception callback processing has ended.
3010
 *
3011
 *        /!\ This version of the ISR supports double buffering but does not support automatic RX re-enabling!
3012
 *
3013
 * NOTE:  In PC based system using (Cheetah or ARM) USB to SPI converter there can be no interrupts, however we still need something
3014
 *        to take the place of it and operate in a polled way. In an embedded system this function should be configured to be triggered
3015
 *        on any of the interrupts described above.
3016

3017
 * input parameters
3018
 *
3019
 * output parameters
3020
 *
3021
 * no return value
3022
 */
3023
void dwt_isr(void)
3024
{
3025
    uint32_t status = pdw1000local->cbData.status = dwt_read32bitreg(SYS_STATUS_ID); // Read status register low 32bits
3026
3027
    // Handle RX good frame event
3028
    if(status & SYS_STATUS_RXFCG)
3029
    {
3030
        uint16_t finfo16;
3031
        uint16_t len;
3032
3033
        dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_GOOD); // Clear all receive status bits
3034
3035
        pdw1000local->cbData.rx_flags = 0;
3036
3037
        // Read frame info - Only the first two bytes of the register are used here.
3038
        finfo16 = dwt_read16bitoffsetreg(RX_FINFO_ID, RX_FINFO_OFFSET);
3039
3040
        // Report frame length - Standard frame length up to 127, extended frame length up to 1023 bytes
3041
        len = finfo16 & RX_FINFO_RXFL_MASK_1023;
3042
        if(pdw1000local->longFrames == 0)
3043
        {
3044
            len &= RX_FINFO_RXFLEN_MASK;
3045
        }
3046
        pdw1000local->cbData.datalength = len;
3047
3048
        // Report ranging bit
3049
        if(finfo16 & RX_FINFO_RNG)
3050
        {
3051
            pdw1000local->cbData.rx_flags |= DWT_CB_DATA_RX_FLAG_RNG;
3052
        }
3053
3054
        // Report frame control - First bytes of the received frame.
3055
        dwt_readfromdevice(RX_BUFFER_ID, 0, FCTRL_LEN_MAX, pdw1000local->cbData.fctrl);
3056
3057
        // Because of a previous frame not being received properly, AAT bit can be set upon the proper reception of a frame not requesting for
3058
        // acknowledgement (ACK frame is not actually sent though). If the AAT bit is set, check ACK request bit in frame control to confirm (this
3059
        // implementation works only for IEEE802.15.4-2011 compliant frames).
3060
        // This issue is not documented at the time of writing this code. It should be in next release of DW1000 User Manual (v2.09, from July 2016).
3061
        if((status & SYS_STATUS_AAT) && ((pdw1000local->cbData.fctrl[0] & FCTRL_ACK_REQ_MASK) == 0))
3062
        {
3063
            dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_AAT); // Clear AAT status bit in register
3064
            pdw1000local->cbData.status &= ~SYS_STATUS_AAT; // Clear AAT status bit in callback data register copy
3065
            pdw1000local->wait4resp = 0;
3066
        }
3067
3068
        // Call the corresponding callback if present
3069
        if(pdw1000local->cbRxOk != NULL)
3070
        {
3071
            pdw1000local->cbRxOk(&pdw1000local->cbData);
3072
        }
3073
3074
        if (pdw1000local->dblbuffon)
3075
        {
3076
            // Toggle the Host side Receive Buffer Pointer
3077
            dwt_write8bitoffsetreg(SYS_CTRL_ID, SYS_CTRL_HRBT_OFFSET, 1);
3078
        }
3079
    }
3080
3081
    // Handle TX confirmation event
3082
    if(status & SYS_STATUS_TXFRS)
3083
    {
3084
        dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_TX); // Clear TX event bits
3085
3086
        // In the case where this TXFRS interrupt is due to the automatic transmission of an ACK solicited by a response (with ACK request bit set)
3087
        // that we receive through using wait4resp to a previous TX (and assuming that the IRQ processing of that TX has already been handled), then
3088
        // we need to handle the IC issue which turns on the RX again in this situation (i.e. because it is wrongly applying the wait4resp after the
3089
        // ACK TX).
3090
        // See section "Transmit and automatically wait for response" in DW1000 User Manual
3091
        if((status & SYS_STATUS_AAT) && pdw1000local->wait4resp)
3092
        {
3093
            dwt_forcetrxoff(); // Turn the RX off
3094
            dwt_rxreset(); // Reset in case we were late and a frame was already being received
3095
        }
3096
3097
        // Call the corresponding callback if present
3098
        if(pdw1000local->cbTxDone != NULL)
3099
        {
3100
            pdw1000local->cbTxDone(&pdw1000local->cbData);
3101
        }
3102
    }
3103
3104
    // Handle frame reception/preamble detect timeout events
3105
    if(status & SYS_STATUS_ALL_RX_TO)
3106
    {
3107
        dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXRFTO); // Clear RX timeout event bits
3108
3109
        pdw1000local->wait4resp = 0;
3110
3111
        // Because of an issue with receiver restart after error conditions, an RX reset must be applied after any error or timeout event to ensure
3112
        // the next good frame's timestamp is computed correctly.
3113
        // See section "RX Message timestamp" in DW1000 User Manual.
3114
        dwt_forcetrxoff();
3115
        dwt_rxreset();
3116
3117
        // Call the corresponding callback if present
3118
        if(pdw1000local->cbRxTo != NULL)
3119
        {
3120
            pdw1000local->cbRxTo(&pdw1000local->cbData);
3121
        }
3122
    }
3123
3124
    // Handle RX errors events
3125
    if(status & SYS_STATUS_ALL_RX_ERR)
3126
    {
3127
        dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR); // Clear RX error event bits
3128
3129
        pdw1000local->wait4resp = 0;
3130
3131
        // Because of an issue with receiver restart after error conditions, an RX reset must be applied after any error or timeout event to ensure
3132
        // the next good frame's timestamp is computed correctly.
3133
        // See section "RX Message timestamp" in DW1000 User Manual.
3134
        dwt_forcetrxoff();
3135
        dwt_rxreset();
3136
3137
        // Call the corresponding callback if present
3138
        if(pdw1000local->cbRxErr != NULL)
3139
        {
3140
            pdw1000local->cbRxErr(&pdw1000local->cbData);
3141
        }
3142
    }
3143
}
3144
3145
/*! ------------------------------------------------------------------------------------------------------------------
3146
 * @fn dwt_isr_lplisten()
3147
 *
3148
 * @brief This is the DW1000's Interrupt Service Routine to use when low-power listening scheme is implemented. It will
3149
 *        only process/report the RXFCG event (through cbRxOk callback).
3150
 *        It clears RXFCG interrupt and reads received frame information and frame control before calling the callback.
3151
 *
3152
 *        /!\ This version of the ISR is designed for single buffering case only!
3153
 *
3154
 * input parameters
3155
 *
3156
 * output parameters
3157
 *
3158
 * no return value
3159
 */
3160
void dwt_lowpowerlistenisr(void)
3161
{
3162
    uint32_t status = pdw1000local->cbData.status = dwt_read32bitreg(SYS_STATUS_ID); // Read status register low 32bits
3163
    uint16_t finfo16;
3164
    uint16_t len;
3165
3166
    // The only interrupt handled when in low-power listening mode is RX good frame so proceed directly to the handling of the received frame.
3167
3168
    // Deactivate low-power listening before clearing the interrupt. If not, the DW1000 will go back to sleep as soon as the interrupt is cleared.
3169
    dwt_setlowpowerlistening(0);
3170
3171
    dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_GOOD); // Clear all receive status bits
3172
3173
    pdw1000local->cbData.rx_flags = 0;
3174
3175
    // Read frame info - Only the first two bytes of the register are used here.
3176
    finfo16 = dwt_read16bitoffsetreg(RX_FINFO_ID, 0);
3177
3178
    // Report frame length - Standard frame length up to 127, extended frame length up to 1023 bytes
3179
    len = finfo16 & RX_FINFO_RXFL_MASK_1023;
3180
    if(pdw1000local->longFrames == 0)
3181
    {
3182
        len &= RX_FINFO_RXFLEN_MASK;
3183
    }
3184
    pdw1000local->cbData.datalength = len;
3185
3186
    // Report ranging bit
3187
    if(finfo16 & RX_FINFO_RNG)
3188
    {
3189
        pdw1000local->cbData.rx_flags |= DWT_CB_DATA_RX_FLAG_RNG;
3190
    }
3191
3192
    // Report frame control - First bytes of the received frame.
3193
    dwt_readfromdevice(RX_BUFFER_ID, 0, FCTRL_LEN_MAX, pdw1000local->cbData.fctrl);
3194
3195
    // Because of a previous frame not being received properly, AAT bit can be set upon the proper reception of a frame not requesting for
3196
    // acknowledgement (ACK frame is not actually sent though). If the AAT bit is set, check ACK request bit in frame control to confirm (this
3197
    // implementation works only for IEEE802.15.4-2011 compliant frames).
3198
    // This issue is not documented at the time of writing this code. It should be in next release of DW1000 User Manual (v2.09, from July 2016).
3199
    if((status & SYS_STATUS_AAT) && ((pdw1000local->cbData.fctrl[0] & FCTRL_ACK_REQ_MASK) == 0))
3200
    {
3201
        dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_AAT); // Clear AAT status bit in register
3202
        pdw1000local->cbData.status &= ~SYS_STATUS_AAT; // Clear AAT status bit in callback data register copy
3203
        pdw1000local->wait4resp = 0;
3204
    }
3205
3206
    // Call the corresponding callback if present
3207
    if(pdw1000local->cbRxOk != NULL)
3208
    {
3209
        pdw1000local->cbRxOk(&pdw1000local->cbData);
3210
    }
3211
}
3212
3213
/*! ------------------------------------------------------------------------------------------------------------------
3214
 * @fn dwt_setleds()
3215
 *
3216
 * @brief This is used to set up Tx/Rx GPIOs which could be used to control LEDs
3217
 * Note: not completely IC dependent, also needs board with LEDS fitted on right I/O lines
3218
 *       this function enables GPIOs 2 and 3 which are connected to LED3 and LED4 on EVB1000
3219
 *
3220
 * input parameters
3221
 * @param mode - this is a bit field interpreted as follows:
3222
 *          - bit 0: 1 to enable LEDs, 0 to disable them
3223
 *          - bit 1: 1 to make LEDs blink once on init. Only valid if bit 0 is set (enable LEDs)
3224
 *          - bit 2 to 7: reserved
3225
 *
3226
 * output parameters none
3227
 *
3228
 * no return value
3229
 */
3230
void dwt_setleds(uint8_t mode)
3231
{
3232
    uint32_t reg;
3233
3234
    if (mode & DWT_LEDS_ENABLE)
3235
    {
3236
        // Set up MFIO for LED output.
3237
        reg = dwt_read32bitoffsetreg(GPIO_CTRL_ID, GPIO_MODE_OFFSET);
3238
        reg &= ~(GPIO_MSGP2_MASK | GPIO_MSGP3_MASK);
3239
        reg |= (GPIO_PIN2_RXLED | GPIO_PIN3_TXLED);
3240
        dwt_write32bitoffsetreg(GPIO_CTRL_ID, GPIO_MODE_OFFSET, reg);
3241
3242
        // Enable LP Oscillator to run from counter and turn on de-bounce clock.
3243
        reg = dwt_read32bitoffsetreg(PMSC_ID, PMSC_CTRL0_OFFSET);
3244
        reg |= (PMSC_CTRL0_GPDCE | PMSC_CTRL0_KHZCLEN);
3245
        dwt_write32bitoffsetreg(PMSC_ID, PMSC_CTRL0_OFFSET, reg);
3246
3247
        // Enable LEDs to blink and set default blink time.
3248
        reg = PMSC_LEDC_BLNKEN | PMSC_LEDC_BLINK_TIME_DEF;
3249
        // Make LEDs blink once if requested.
3250
        if (mode & DWT_LEDS_INIT_BLINK)
3251
        {
3252
            reg |= PMSC_LEDC_BLINK_NOW_ALL;
3253
        }
3254
        dwt_write32bitoffsetreg(PMSC_ID, PMSC_LEDC_OFFSET, reg);
3255
        // Clear force blink bits if needed.
3256
        if(mode & DWT_LEDS_INIT_BLINK)
3257
        {
3258
            reg &= ~PMSC_LEDC_BLINK_NOW_ALL;
3259
            dwt_write32bitoffsetreg(PMSC_ID, PMSC_LEDC_OFFSET, reg);
3260
        }
3261
    }
3262
    else
3263
    {
3264
        // Clear the GPIO bits that are used for LED control.
3265
        reg = dwt_read32bitoffsetreg(GPIO_CTRL_ID, GPIO_MODE_OFFSET);
3266
        reg &= ~(GPIO_MSGP2_MASK | GPIO_MSGP3_MASK);
3267
        dwt_write32bitoffsetreg(GPIO_CTRL_ID, GPIO_MODE_OFFSET, reg);
3268
    }
3269
}
3270
3271
/*! ------------------------------------------------------------------------------------------------------------------
3272
 * @fn _dwt_enableclocks()
3273
 *
3274
 * @brief function to enable/disable clocks to particular digital blocks/system
3275
 *
3276
 * input parameters
3277
 * @param clocks - set of clocks to enable/disable
3278
 *
3279
 * output parameters none
3280
 *
3281
 * no return value
3282
 */
3283
void _dwt_enableclocks(int clocks)
3284
{
3285
    uint8_t reg[2];
3286
3287
    dwt_readfromdevice(PMSC_ID, PMSC_CTRL0_OFFSET, 2, reg);
3288
    switch(clocks)
3289
    {
3290
        case ENABLE_ALL_SEQ:
3291
        {
3292
            reg[0] = 0x00 ;
3293
            reg[1] = reg[1] & 0xfe;
3294
        }
3295
        break;
3296
        case FORCE_SYS_XTI:
3297
        {
3298
            // System and RX
3299
            reg[0] = 0x01 | (reg[0] & 0xfc);
3300
        }
3301
        break;
3302
        case FORCE_SYS_PLL:
3303
        {
3304
            // System
3305
            reg[0] = 0x02 | (reg[0] & 0xfc);
3306
        }
3307
        break;
3308
        case READ_ACC_ON:
3309
        {
3310
            reg[0] = 0x48 | (reg[0] & 0xb3);
3311
            reg[1] = 0x80 | reg[1];
3312
        }
3313
        break;
3314
        case READ_ACC_OFF:
3315
        {
3316
            reg[0] = reg[0] & 0xb3;
3317
            reg[1] = 0x7f & reg[1];
3318
        }
3319
        break;
3320
        case FORCE_OTP_ON:
3321
        {
3322
            reg[1] = 0x02 | reg[1];
3323
        }
3324
        break;
3325
        case FORCE_OTP_OFF:
3326
        {
3327
            reg[1] = reg[1] & 0xfd;
3328
        }
3329
        break;
3330
        case FORCE_TX_PLL:
3331
        {
3332
            reg[0] = 0x20 | (reg[0] & 0xcf);
3333
        }
3334
        break;
3335
        case FORCE_LDE:
3336
        {
3337
            reg[0] = 0x01;
3338
            reg[1] = 0x03;
3339
        }
3340
        break;
3341
        default:
3342
        break;
3343
    }
3344
3345
3346
    // Need to write lower byte separately before setting the higher byte(s)
3347
    dwt_writetodevice(PMSC_ID, PMSC_CTRL0_OFFSET, 1, &reg[0]);
3348
    dwt_writetodevice(PMSC_ID, 0x1, 1, &reg[1]);
3349
3350
} // end _dwt_enableclocks()
3351
3352
/*! ------------------------------------------------------------------------------------------------------------------
3353
 * @fn _dwt_disablesequencing()
3354
 *
3355
 * @brief This function disables the TX blocks sequencing, it disables PMSC control of RF blocks, system clock is also set to XTAL
3356
 *
3357
 * input parameters none
3358
 *
3359
 * output parameters none
3360
 *
3361
 * no return value
3362
 */
3363
void _dwt_disablesequencing(void) // Disable sequencing and go to state "INIT"
3364
{
3365
    _dwt_enableclocks(FORCE_SYS_XTI); // Set system clock to XTI
3366
3367
    dwt_write16bitoffsetreg(PMSC_ID, PMSC_CTRL1_OFFSET, PMSC_CTRL1_PKTSEQ_DISABLE); // Disable PMSC ctrl of RF and RX clk blocks
3368
}
3369
3370
/*! ------------------------------------------------------------------------------------------------------------------
3371
 * @fn dwt_setdelayedtrxtime()
3372
 *
3373
 * @brief This API function configures the delayed transmit time or the delayed RX on time
3374
 *
3375
 * input parameters
3376
 * @param starttime - the TX/RX start time (the 32 bits should be the high 32 bits of the system time at which to send the message,
3377
 * or at which to turn on the receiver)
3378
 *
3379
 * output parameters none
3380
 *
3381
 * no return value
3382
 */
3383
void dwt_setdelayedtrxtime(uint32_t starttime)
3384
{
3385
    dwt_write32bitoffsetreg(DX_TIME_ID, 1, starttime); // Write at offset 1 as the lower 9 bits of this register are ignored
3386
3387
} // end dwt_setdelayedtrxtime()
3388
3389
/*! ------------------------------------------------------------------------------------------------------------------
3390
 * @fn dwt_starttx()
3391
 *
3392
 * @brief This call initiates the transmission, input parameter indicates which TX mode is used see below
3393
 *
3394
 * input parameters:
3395
 * @param mode - if 0 immediate TX (no response expected)
3396
 *               if 1 delayed TX (no response expected)
3397
 *               if 2 immediate TX (response expected - so the receiver will be automatically turned on after TX is done)
3398
 *               if 3 delayed TX (response expected - so the receiver will be automatically turned on after TX is done)
3399
 *
3400
 * output parameters
3401
 *
3402
 * returns DWT_SUCCESS for success, or DWT_ERROR for error (e.g. a delayed transmission will fail if the delayed time has passed)
3403
 */
3404
int dwt_starttx(uint8_t mode)
3405
{
3406
    int retval = DWT_SUCCESS ;
3407
    uint8_t temp  = 0x00;
3408
    uint16_t checkTxOK = 0 ;
3409
3410
    if(mode & DWT_RESPONSE_EXPECTED)
3411
    {
3412
        temp = (uint8_t)SYS_CTRL_WAIT4RESP ; // Set wait4response bit
3413
        dwt_write8bitoffsetreg(SYS_CTRL_ID, SYS_CTRL_OFFSET, temp);
3414
        pdw1000local->wait4resp = 1;
3415
    }
3416
3417
    if (mode & DWT_START_TX_DELAYED)
3418
    {
3419
        // Both SYS_CTRL_TXSTRT and SYS_CTRL_TXDLYS to correctly enable TX
3420
        temp |= (uint8_t)(SYS_CTRL_TXDLYS | SYS_CTRL_TXSTRT) ;
3421
        dwt_write8bitoffsetreg(SYS_CTRL_ID, SYS_CTRL_OFFSET, temp);
3422
        checkTxOK = dwt_read16bitoffsetreg(SYS_STATUS_ID, 3); // Read at offset 3 to get the upper 2 bytes out of 5
3423
        if ((checkTxOK & SYS_STATUS_TXERR) == 0) // Transmit Delayed Send set over Half a Period away or Power Up error (there is enough time to send but not to power up individual blocks).
3424
        {
3425
            retval = DWT_SUCCESS ; // All okay
3426
        }
3427
        else
3428
        {
3429
            // I am taking DSHP set to Indicate that the TXDLYS was set too late for the specified DX_TIME.
3430
            // Remedial Action - (a) cancel delayed send
3431
            temp = (uint8_t)SYS_CTRL_TRXOFF; // This assumes the bit is in the lowest byte
3432
            dwt_write8bitoffsetreg(SYS_CTRL_ID, SYS_CTRL_OFFSET, temp);
3433
            // Note event Delayed TX Time too Late
3434
            // Could fall through to start a normal send (below) just sending late.....
3435
            // ... instead return and assume return value of 1 will be used to detect and recover from the issue.
3436
            pdw1000local->wait4resp = 0;
3437
            retval = DWT_ERROR ; // Failed !
3438
        }
3439
    }
3440
    else
3441
    {
3442
        temp |= (uint8_t)SYS_CTRL_TXSTRT ;
3443
        dwt_write8bitoffsetreg(SYS_CTRL_ID, SYS_CTRL_OFFSET, temp);
3444
    }
3445
3446
    return retval;
3447
3448
} // end dwt_starttx()
3449
3450
/*! ------------------------------------------------------------------------------------------------------------------
3451
 * @fn dwt_forcetrxoff()
3452
 *
3453
 * @brief This is used to turn off the transceiver
3454
 *
3455
 * input parameters
3456
 *
3457
 * output parameters
3458
 *
3459
 * no return value
3460
 */
3461
void dwt_forcetrxoff(void)
3462
{
3463
    decaIrqStatus_t stat ;
3464
    uint32_t mask;
3465
3466
    mask = dwt_read32bitreg(SYS_MASK_ID) ; // Read set interrupt mask
3467
3468
    // Need to beware of interrupts occurring in the middle of following read modify write cycle
3469
    // We can disable the radio, but before the status is cleared an interrupt can be set (e.g. the
3470
    // event has just happened before the radio was disabled)
3471
    // thus we need to disable interrupt during this operation
3472
    stat = decamutexon() ;
3473
3474
    dwt_write32bitreg(SYS_MASK_ID, 0) ; // Clear interrupt mask - so we don't get any unwanted events
3475
3476
    dwt_write8bitoffsetreg(SYS_CTRL_ID, SYS_CTRL_OFFSET, (uint8_t)SYS_CTRL_TRXOFF) ; // Disable the radio
3477
3478
    // Forcing Transceiver off - so we do not want to see any new events that may have happened
3479
    dwt_write32bitreg(SYS_STATUS_ID, (SYS_STATUS_ALL_TX | SYS_STATUS_ALL_RX_ERR | SYS_STATUS_ALL_RX_TO | SYS_STATUS_ALL_RX_GOOD));
3480
3481
    dwt_syncrxbufptrs();
3482
3483
    dwt_write32bitreg(SYS_MASK_ID, mask) ; // Set interrupt mask to what it was
3484
3485
    // Enable/restore interrupts again...
3486
    decamutexoff(stat) ;
3487
    pdw1000local->wait4resp = 0;
3488
3489
} // end deviceforcetrxoff()
3490
3491
/*! ------------------------------------------------------------------------------------------------------------------
3492
 * @fn dwt_syncrxbufptrs()
3493
 *
3494
 * @brief this function synchronizes rx buffer pointers
3495
 * need to make sure that the host/IC buffer pointers are aligned before starting RX
3496
 *
3497
 * input parameters:
3498
 *
3499
 * output parameters
3500
 *
3501
 * no return value
3502
 */
3503
void dwt_syncrxbufptrs(void)
3504
{
3505
    uint8_t  buff ;
3506
    // Need to make sure that the host/IC buffer pointers are aligned before starting RX
3507
    buff = dwt_read8bitoffsetreg(SYS_STATUS_ID, 3); // Read 1 byte at offset 3 to get the 4th byte out of 5
3508
3509
    if((buff & (SYS_STATUS_ICRBP >> 24)) !=     // IC side Receive Buffer Pointer
3510
       ((buff & (SYS_STATUS_HSRBP>>24)) << 1) ) // Host Side Receive Buffer Pointer
3511
    {
3512
        dwt_write8bitoffsetreg(SYS_CTRL_ID, SYS_CTRL_HRBT_OFFSET , 0x01) ; // We need to swap RX buffer status reg (write one to toggle internally)
3513
    }
3514
}
3515
3516
/*! ------------------------------------------------------------------------------------------------------------------
3517
 * @fn dwt_setsniffmode()
3518
 *
3519
 * @brief enable/disable and configure SNIFF mode.
3520
 *
3521
 * SNIFF mode is a low-power reception mode where the receiver is sequenced on and off instead of being on all the time.
3522
 * The time spent in each state (on/off) is specified through the parameters below.
3523
 * See DW1000 User Manual section 4.5 "Low-Power SNIFF mode" for more details.
3524
 *
3525
 * input parameters:
3526
 * @param enable - 1 to enable SNIFF mode, 0 to disable. When 0, all other parameters are not taken into account.
3527
 * @param timeOn - duration of receiver ON phase, expressed in multiples of PAC size. The counter automatically adds 1 PAC
3528
 *                 size to the value set. Min value that can be set is 1 (i.e. an ON time of 2 PAC size), max value is 15.
3529
 * @param timeOff - duration of receiver OFF phase, expressed in multiples of 128/125 µs (~1 µs). Max value is 255.
3530
 *
3531
 * output parameters
3532
 *
3533
 * no return value
3534
 */
3535
void dwt_setsniffmode(int enable, uint8_t timeOn, uint8_t timeOff)
3536
{
3537
    uint32_t pmsc_reg;
3538
    if (enable)
3539
    {
3540
        /* Configure ON/OFF times and enable PLL2 on/off sequencing by SNIFF mode. */
3541
        uint16_t sniff_reg = ((timeOff << 8) | timeOn) & RX_SNIFF_MASK;
3542
        dwt_write16bitoffsetreg(RX_SNIFF_ID, RX_SNIFF_OFFSET, sniff_reg);
3543
        pmsc_reg = dwt_read32bitoffsetreg(PMSC_ID, PMSC_CTRL0_OFFSET);
3544
        pmsc_reg |= PMSC_CTRL0_PLL2_SEQ_EN;
3545
        dwt_write32bitoffsetreg(PMSC_ID, PMSC_CTRL0_OFFSET, pmsc_reg);
3546
    }
3547
    else
3548
    {
3549
        /* Clear ON/OFF times and disable PLL2 on/off sequencing by SNIFF mode. */
3550
        dwt_write16bitoffsetreg(RX_SNIFF_ID, RX_SNIFF_OFFSET, 0x0000);
3551
        pmsc_reg = dwt_read32bitoffsetreg(PMSC_ID, PMSC_CTRL0_OFFSET);
3552
        pmsc_reg &= ~PMSC_CTRL0_PLL2_SEQ_EN;
3553
        dwt_write32bitoffsetreg(PMSC_ID, PMSC_CTRL0_OFFSET, pmsc_reg);
3554
    }
3555
}
3556
3557
/*! ------------------------------------------------------------------------------------------------------------------
3558
 * @fn dwt_setlowpowerlistening()
3559
 *
3560
 * @brief enable/disable low-power listening mode.
3561
 *
3562
 * Low-power listening is a feature whereby the DW1000 is predominantly in the SLEEP state but wakes periodically, (after
3563
 * this "long sleep"), for a very short time to sample the air for a preamble sequence. This preamble sampling "listening"
3564
 * phase is actually two reception phases separated by a "short sleep" time. See DW1000 User Manual section "Low-Power
3565
 * Listening" for more details.
3566
 *
3567
 * NOTE: Before enabling low-power listening, the following functions have to be called to fully configure it:
3568
 *           - dwt_configuresleep() to configure long sleep phase. "mode" parameter should at least have DWT_PRESRV_SLEEP,
3569
 *             DWT_CONFIG and DWT_RX_EN set and "wake" parameter should at least have both DWT_WAKE_SLPCNT and DWT_SLP_EN set.
3570
 *           - dwt_calibratesleepcnt() and dwt_configuresleepcnt() to define the "long sleep" phase duration.
3571
 *           - dwt_setsnoozetime() to define the "short sleep" phase duration.
3572
 *           - dwt_setpreambledetecttimeout() to define the reception phases duration.
3573
 *           - dwt_setinterrupt() to activate RX good frame interrupt (DWT_INT_RFCG) only.
3574
 *       When configured, low-power listening mode can be triggered either by putting the DW1000 to sleep (using
3575
 *       dwt_entersleep()) or by activating reception (using dwt_rxenable()).
3576
 *
3577
 *       Please refer to the low-power listening examples (examples 8a/8b accompanying the API distribution on Decawave's
3578
 *       website). They form a working example code that shows how to use low-power listening correctly.
3579
 *
3580
 * input parameters:
3581
 * @param enable - 1 to enable low-power listening, 0 to disable.
3582
 *
3583
 * output parameters
3584
 *
3585
 * no return value
3586
 */
3587
void dwt_setlowpowerlistening(int enable)
3588
{
3589
    uint32_t pmsc_reg = dwt_read32bitoffsetreg(PMSC_ID, PMSC_CTRL1_OFFSET);
3590
    if (enable)
3591
    {
3592
        /* Configure RX to sleep and snooze features. */
3593
        pmsc_reg |= (PMSC_CTRL1_ARXSLP | PMSC_CTRL1_SNOZE);
3594
    }
3595
    else
3596
    {
3597
        /* Reset RX to sleep and snooze features. */
3598
        pmsc_reg &= ~(PMSC_CTRL1_ARXSLP | PMSC_CTRL1_SNOZE);
3599
    }
3600
    dwt_write32bitoffsetreg(PMSC_ID, PMSC_CTRL1_OFFSET, pmsc_reg);
3601
}
3602
3603
/*! ------------------------------------------------------------------------------------------------------------------
3604
 * @fn dwt_setsnoozetime()
3605
 *
3606
 * @brief Set duration of "short sleep" phase when in low-power listening mode.
3607
 *
3608
 * input parameters:
3609
 * @param snooze_time - "short sleep" phase duration, expressed in multiples of 512/19.2 µs (~26.7 µs). The counter
3610
 *                      automatically adds 1 to the value set. The smallest working value that should be set is 1,
3611
 *                      i.e. giving a snooze time of 2 units (or ~53 µs).
3612
 *
3613
 * output parameters
3614
 *
3615
 * no return value
3616
 */
3617
void dwt_setsnoozetime(uint8_t snooze_time)
3618
{
3619
    dwt_write8bitoffsetreg(PMSC_ID, PMSC_SNOZT_OFFSET, snooze_time);
3620
}
3621
3622
/*! ------------------------------------------------------------------------------------------------------------------
3623
 * @fn dwt_rxenable()
3624
 *
3625
 * @brief This call turns on the receiver, can be immediate or delayed (depending on the mode parameter). In the case of a
3626
 * "late" error the receiver will only be turned on if the DWT_IDLE_ON_DLY_ERR is not set.
3627
 * The receiver will stay turned on, listening to any messages until
3628
 * it either receives a good frame, an error (CRC, PHY header, Reed Solomon) or  it times out (SFD, Preamble or Frame).
3629
 *
3630
 * input parameters
3631
 * @param mode - this can be one of the following allowed values:
3632
 *
3633
 * DWT_START_RX_IMMEDIATE      0 used to enbale receiver immediately
3634
 * DWT_START_RX_DELAYED        1 used to set up delayed RX, if "late" error triggers, then the RX will be enabled immediately
3635
 * (DWT_START_RX_DELAYED | DWT_IDLE_ON_DLY_ERR) 3 used to disable re-enabling of receiver if delayed RX failed due to "late" error
3636
 * (DWT_START_RX_IMMEDIATE | DWT_NO_SYNC_PTRS) 4 used to re-enable RX without trying to sync IC and host side buffer pointers, typically when
3637
 *                                               performing manual RX re-enabling in double buffering mode
3638
 *
3639
 * returns DWT_SUCCESS for success, or DWT_ERROR for error (e.g. a delayed receive enable will be too far in the future if delayed time has passed)
3640
 */
3641
int dwt_rxenable(int mode)
3642
{
3643
    uint16_t temp ;
3644
    uint8_t temp1 ;
3645
3646
    if ((mode & DWT_NO_SYNC_PTRS) == 0)
3647
    {
3648
        dwt_syncrxbufptrs();
3649
    }
3650
3651
    temp = (uint16_t)SYS_CTRL_RXENAB ;
3652
3653
    if (mode & DWT_START_RX_DELAYED)
3654
    {
3655
        temp |= (uint16_t)SYS_CTRL_RXDLYE ;
3656
    }
3657
3658
    dwt_write16bitoffsetreg(SYS_CTRL_ID, SYS_CTRL_OFFSET, temp);
3659
3660
    if (mode & DWT_START_RX_DELAYED) // check for errors
3661
    {
3662
        temp1 = dwt_read8bitoffsetreg(SYS_STATUS_ID, 3); // Read 1 byte at offset 3 to get the 4th byte out of 5
3663
        if ((temp1 & (SYS_STATUS_HPDWARN >> 24)) != 0) // if delay has passed do immediate RX on unless DWT_IDLE_ON_DLY_ERR is true
3664
        {
3665
            dwt_forcetrxoff(); // turn the delayed receive off
3666
3667
            if((mode & DWT_IDLE_ON_DLY_ERR) == 0) // if DWT_IDLE_ON_DLY_ERR not set then re-enable receiver
3668
            {
3669
                dwt_write16bitoffsetreg(SYS_CTRL_ID, SYS_CTRL_OFFSET, SYS_CTRL_RXENAB);
3670
            }
3671
            return DWT_ERROR; // return warning indication
3672
        }
3673
    }
3674
3675
    return DWT_SUCCESS;
3676
} // end dwt_rxenable()
3677
3678
/*! ------------------------------------------------------------------------------------------------------------------
3679
 * @fn dwt_setrxtimeout()
3680
 *
3681
 * @brief This call enables RX timeout (SY_STAT_RFTO event)
3682
 *
3683
 * input parameters
3684
 * @param time - how long the receiver remains on from the RX enable command
3685
 *               The time parameter used here is in 1.0256 us (512/499.2MHz) units
3686
 *               If set to 0 the timeout is disabled.
3687
 *
3688
 * output parameters
3689
 *
3690
 * no return value
3691
 */
3692
void dwt_setrxtimeout(uint16_t time)
3693
{
3694
    uint8_t temp ;
3695
3696
    temp = dwt_read8bitoffsetreg(SYS_CFG_ID, 3); // Read at offset 3 to get the upper byte only
3697
3698
    if(time > 0)
3699
    {
3700
        dwt_write16bitoffsetreg(RX_FWTO_ID, RX_FWTO_OFFSET, time) ;
3701
3702
        temp |= (uint8_t)(SYS_CFG_RXWTOE>>24); // Shift RXWTOE mask as we read the upper byte only
3703
        // OR in 32bit value (1 bit set), I know this is in high byte.
3704
        pdw1000local->sysCFGreg |= SYS_CFG_RXWTOE;
3705
3706
        dwt_write8bitoffsetreg(SYS_CFG_ID, 3, temp); // Write at offset 3 to write the upper byte only
3707
    }
3708
    else
3709
    {
3710
        temp &= ~((uint8_t)(SYS_CFG_RXWTOE>>24)); // Shift RXWTOE mask as we read the upper byte only
3711
        // AND in inverted 32bit value (1 bit clear), I know this is in high byte.
3712
        pdw1000local->sysCFGreg &= ~(SYS_CFG_RXWTOE);
3713
3714
        dwt_write8bitoffsetreg(SYS_CFG_ID, 3, temp); // Write at offset 3 to write the upper byte only
3715
    }
3716
3717
} // end dwt_setrxtimeout()
3718
3719
3720
/*! ------------------------------------------------------------------------------------------------------------------
3721
 * @fn dwt_setpreambledetecttimeout()
3722
 *
3723
 * @brief This call enables preamble timeout (SY_STAT_RXPTO event)
3724
 *
3725
 * input parameters
3726
 * @param  timeout - Preamble detection timeout, expressed in multiples of PAC size. The counter automatically adds 1 PAC
3727
 *                   size to the value set. Min value that can be set is 1 (i.e. a timeout of 2 PAC size).
3728
 *
3729
 * output parameters
3730
 *
3731
 * no return value
3732
 */
3733
void dwt_setpreambledetecttimeout(uint16_t timeout)
3734
{
3735
    dwt_write16bitoffsetreg(DRX_CONF_ID, DRX_PRETOC_OFFSET, timeout);
3736
}
3737
3738
/*! ------------------------------------------------------------------------------------------------------------------
3739
 * @fn void dwt_setinterrupt()
3740
 *
3741
 * @brief This function enables the specified events to trigger an interrupt.
3742
 * The following events can be enabled:
3743
 * DWT_INT_TFRS         0x00000080          // frame sent
3744
 * DWT_INT_RFCG         0x00004000          // frame received with good CRC
3745
 * DWT_INT_RPHE         0x00001000          // receiver PHY header error
3746
 * DWT_INT_RFCE         0x00008000          // receiver CRC error
3747
 * DWT_INT_RFSL         0x00010000          // receiver sync loss error
3748
 * DWT_INT_RFTO         0x00020000          // frame wait timeout
3749
 * DWT_INT_RXPTO        0x00200000          // preamble detect timeout
3750
 * DWT_INT_SFDT         0x04000000          // SFD timeout
3751
 * DWT_INT_ARFE         0x20000000          // frame rejected (due to frame filtering configuration)
3752
 *
3753
 *
3754
 * input parameters:
3755
 * @param bitmask - sets the events which will generate interrupt
3756
 * @param enable - if set the interrupts are enabled else they are cleared
3757
 *
3758
 * output parameters
3759
 *
3760
 * no return value
3761
 */
3762
void dwt_setinterrupt(uint32_t bitmask, uint8_t enable)
3763
{
3764
    decaIrqStatus_t stat ;
3765
    uint32_t mask ;
3766
3767
    // Need to beware of interrupts occurring in the middle of following read modify write cycle
3768
    stat = decamutexon() ;
3769
3770
    mask = dwt_read32bitreg(SYS_MASK_ID) ; // Read register
3771
3772
    if(enable)
3773
    {
3774
        mask |= bitmask ;
3775
    }
3776
    else
3777
    {
3778
        mask &= ~bitmask ; // Clear the bit
3779
    }
3780
    dwt_write32bitreg(SYS_MASK_ID,mask) ; // New value
3781
3782
    decamutexoff(stat) ;
3783
}
3784
3785
/*! ------------------------------------------------------------------------------------------------------------------
3786
 * @fn dwt_configeventcounters()
3787
 *
3788
 * @brief This is used to enable/disable the event counter in the IC
3789
 *
3790
 * input parameters
3791
 * @param - enable - 1 enables (and reset), 0 disables the event counters
3792
 * output parameters
3793
 *
3794
 * no return value
3795
 */
3796
void dwt_configeventcounters(int enable)
3797
{
3798
    // Need to clear and disable, can't just clear
3799
    dwt_write8bitoffsetreg(DIG_DIAG_ID, EVC_CTRL_OFFSET, (uint8_t)(EVC_CLR));
3800
3801
    if(enable)
3802
    {
3803
        dwt_write8bitoffsetreg(DIG_DIAG_ID, EVC_CTRL_OFFSET, (uint8_t)(EVC_EN)); // Enable
3804
    }
3805
}
3806
3807
/*! ------------------------------------------------------------------------------------------------------------------
3808
 * @fn dwt_readeventcounters()
3809
 *
3810
 * @brief This is used to read the event counters in the IC
3811
 *
3812
 * input parameters
3813
 * @param counters - pointer to the dwt_deviceentcnts_t structure which will hold the read data
3814
 *
3815
 * output parameters
3816
 *
3817
 * no return value
3818
 */
3819
void dwt_readeventcounters(dwt_deviceentcnts_t *counters)
3820
{
3821
    uint32_t temp;
3822
3823
    temp= dwt_read32bitoffsetreg(DIG_DIAG_ID, EVC_PHE_OFFSET); // Read sync loss (31-16), PHE (15-0)
3824
    counters->PHE = temp & 0xFFF;
3825
    counters->RSL = (temp >> 16) & 0xFFF;
3826
3827
    temp = dwt_read32bitoffsetreg(DIG_DIAG_ID, EVC_FCG_OFFSET); // Read CRC bad (31-16), CRC good (15-0)
3828
    counters->CRCG = temp & 0xFFF;
3829
    counters->CRCB = (temp >> 16) & 0xFFF;
3830
3831
    temp = dwt_read32bitoffsetreg(DIG_DIAG_ID, EVC_FFR_OFFSET); // Overruns (31-16), address errors (15-0)
3832
    counters->ARFE = temp & 0xFFF;
3833
    counters->OVER = (temp >> 16) & 0xFFF;
3834
3835
    temp = dwt_read32bitoffsetreg(DIG_DIAG_ID, EVC_STO_OFFSET); // Read PTO (31-16), SFDTO (15-0)
3836
    counters->PTO = (temp >> 16) & 0xFFF;
3837
    counters->SFDTO = temp & 0xFFF;
3838
3839
    temp = dwt_read32bitoffsetreg(DIG_DIAG_ID, EVC_FWTO_OFFSET); // Read RX TO (31-16), TXFRAME (15-0)
3840
    counters->TXF = (temp >> 16) & 0xFFF;
3841
    counters->RTO = temp & 0xFFF;
3842
3843
    temp = dwt_read32bitoffsetreg(DIG_DIAG_ID, EVC_HPW_OFFSET); // Read half period warning events
3844
    counters->HPW = temp & 0xFFF;
3845
    counters->TXW = (temp >> 16) & 0xFFF;                       // Power-up warning events
3846
3847
}
3848
3849
/*! ------------------------------------------------------------------------------------------------------------------
3850
 * @fn dwt_rxreset()
3851
 *
3852
 * @brief this function resets the receiver of the DW1000
3853
 *
3854
 * input parameters:
3855
 *
3856
 * output parameters
3857
 *
3858
 * no return value
3859
 */
3860
void dwt_rxreset(void)
3861
{
3862
    // Set RX reset
3863
    dwt_write8bitoffsetreg(PMSC_ID, PMSC_CTRL0_SOFTRESET_OFFSET, PMSC_CTRL0_RESET_RX);
3864
3865
    // Clear RX reset
3866
    dwt_write8bitoffsetreg(PMSC_ID, PMSC_CTRL0_SOFTRESET_OFFSET, PMSC_CTRL0_RESET_CLEAR);
3867
}
3868
3869
/*! ------------------------------------------------------------------------------------------------------------------
3870
 * @fn dwt_softreset()
3871
 *
3872
 * @brief this function resets the DW1000
3873
 *
3874
 * input parameters:
3875
 *
3876
 * output parameters
3877
 *
3878
 * no return value
3879
 */
3880
void dwt_softreset(void)
3881
{
3882
    _dwt_disablesequencing();
3883
3884
    // Clear any AON auto download bits (as reset will trigger AON download)
3885
    dwt_write16bitoffsetreg(AON_ID, AON_WCFG_OFFSET, 0x00);
3886
    // Clear the wake-up configuration
3887
    dwt_write8bitoffsetreg(AON_ID, AON_CFG0_OFFSET, 0x00);
3888
    // Upload the new configuration
3889
    _dwt_aonarrayupload();
3890
3891
    // Reset HIF, TX, RX and PMSC
3892
    dwt_write8bitoffsetreg(PMSC_ID, PMSC_CTRL0_SOFTRESET_OFFSET, PMSC_CTRL0_RESET_ALL);
3893
3894
    // DW1000 needs a 10us sleep to let clk PLL lock after reset - the PLL will automatically lock after the reset
3895
    // Could also have polled the PLL lock flag, but then the SPI needs to be < 3MHz !! So a simple delay is easier
3896
    deca_sleep(1);
3897
3898
    // Clear reset
3899
    dwt_write8bitoffsetreg(PMSC_ID, PMSC_CTRL0_SOFTRESET_OFFSET, PMSC_CTRL0_RESET_CLEAR);
3900
3901
    pdw1000local->wait4resp = 0;
3902
}
3903
3904
/*! ------------------------------------------------------------------------------------------------------------------
3905
 * @fn dwt_setxtaltrim()
3906
 *
3907
 * @brief This is used to adjust the crystal frequency
3908
 *
3909
 * input parameters:
3910
 * @param   value - crystal trim value (in range 0x0 to 0x1F) 31 steps (~1.5ppm per step)
3911
 *
3912
 * output parameters
3913
 *
3914
 * no return value
3915
 */
3916
void dwt_setxtaltrim(uint8_t value)
3917
{
3918
    // The 3 MSb in this 8-bit register must be kept to 0b011 to avoid any malfunction.
3919
    uint8_t reg_val = (3 << 5) | (value & FS_XTALT_MASK);
3920
    dwt_write8bitoffsetreg(FS_CTRL_ID, FS_XTALT_OFFSET, reg_val);
3921
}
3922
3923
/*! ------------------------------------------------------------------------------------------------------------------
3924
 * @fn dwt_getinitxtaltrim()
3925
 *
3926
 * @brief This function returns the value of XTAL trim that has been applied during initialisation (dwt_init). This can
3927
 *        be either the value read in OTP memory or a default value.
3928
 *
3929
 * NOTE: The value returned by this function is the initial value only! It is not updated on dwt_setxtaltrim calls.
3930
 *
3931
 * input parameters
3932
 *
3933
 * output parameters
3934
 *
3935
 * returns the XTAL trim value set upon initialisation
3936
 */
3937
uint8_t dwt_getinitxtaltrim(void)
3938
{
3939
    return pdw1000local->init_xtrim;
3940
}
3941
3942
/*! ------------------------------------------------------------------------------------------------------------------
3943
 * @fn dwt_configcwmode()
3944
 *
3945
 * @brief this function sets the DW1000 to transmit cw signal at specific channel frequency
3946
 *
3947
 * input parameters:
3948
 * @param chan - specifies the operating channel (e.g. 1, 2, 3, 4, 5, 6 or 7)
3949
 *
3950
 * output parameters
3951
 *
3952
 * no return value
3953
 */
3954
void dwt_configcwmode(uint8_t chan)
3955
{
3956
#ifdef DWT_API_ERROR_CHECK
3957
    assert((chan >= 1) && (chan <= 7) && (chan != 6));
3958
#endif
3959
3960
    //
3961
    // Disable TX/RX RF block sequencing (needed for cw frame mode)
3962
    //
3963
    _dwt_disablesequencing();
3964
3965
    // Config RF pll (for a given channel)
3966
    // Configure PLL2/RF PLL block CFG/TUNE
3967
    dwt_write32bitoffsetreg(FS_CTRL_ID, FS_PLLCFG_OFFSET, fs_pll_cfg[chan_idx[chan]]);
3968
    dwt_write8bitoffsetreg(FS_CTRL_ID, FS_PLLTUNE_OFFSET, fs_pll_tune[chan_idx[chan]]);
3969
    // PLL wont be enabled until a TX/RX enable is issued later on
3970
    // Configure RF TX blocks (for specified channel and prf)
3971
    // Config RF TX control
3972
    dwt_write32bitoffsetreg(RF_CONF_ID, RF_TXCTRL_OFFSET, tx_config[chan_idx[chan]]);
3973
3974
    //
3975
    // Enable RF PLL
3976
    //
3977
    dwt_write32bitreg(RF_CONF_ID, RF_CONF_TXPLLPOWEN_MASK); // Enable LDO and RF PLL blocks
3978
    dwt_write32bitreg(RF_CONF_ID, RF_CONF_TXALLEN_MASK); // Enable the rest of TX blocks
3979
3980
    //
3981
    // Configure TX clocks
3982
    //
3983
    dwt_write8bitoffsetreg(PMSC_ID, PMSC_CTRL0_OFFSET, 0x22);
3984
    dwt_write8bitoffsetreg(PMSC_ID, 0x1, 0x07);
3985
3986
    // Disable fine grain TX sequencing
3987
    dwt_setfinegraintxseq(0);
3988
3989
    // Configure CW mode
3990
    dwt_write8bitoffsetreg(TX_CAL_ID, TC_PGTEST_OFFSET, TC_PGTEST_CW);
3991
}
3992
3993
/*! ------------------------------------------------------------------------------------------------------------------
3994
 * @fn dwt_configcontinuousframemode()
3995
 *
3996
 * @brief this function sets the DW1000 to continuous tx frame mode for regulatory approvals testing.
3997
 *
3998
 * input parameters:
3999
 * @param framerepetitionrate - This is a 32-bit value that is used to set the interval between transmissions.
4000
*  The minimum value is 4. The units are approximately 8 ns. (or more precisely 512/(499.2e6*128) seconds)).
4001
 *
4002
 * output parameters
4003
 *
4004
 * no return value
4005
 */
4006
void dwt_configcontinuousframemode(uint32_t framerepetitionrate)
4007
{
4008
    //
4009
    // Disable TX/RX RF block sequencing (needed for continuous frame mode)
4010
    //
4011
    _dwt_disablesequencing();
4012
4013
    //
4014
    // Enable RF PLL and TX blocks
4015
    //
4016
    dwt_write32bitreg(RF_CONF_ID, RF_CONF_TXPLLPOWEN_MASK); // Enable LDO and RF PLL blocks
4017
    dwt_write32bitreg(RF_CONF_ID, RF_CONF_TXALLEN_MASK); // Enable the rest of TX blocks
4018
4019
    //
4020
    // Configure TX clocks
4021
    //
4022
    _dwt_enableclocks(FORCE_SYS_PLL);
4023
    _dwt_enableclocks(FORCE_TX_PLL);
4024
4025
    // Set the frame repetition rate
4026
    if(framerepetitionrate < 4)
4027
    {
4028
        framerepetitionrate = 4;
4029
    }
4030
    dwt_write32bitreg(DX_TIME_ID, framerepetitionrate);
4031
4032
    //
4033
    // Configure continuous frame TX
4034
    //
4035
    dwt_write8bitoffsetreg(DIG_DIAG_ID, DIAG_TMC_OFFSET, (uint8_t)(DIAG_TMC_TX_PSTM)); // Turn the tx power spectrum test mode - continuous sending of frames
4036
}
4037
4038
/*! ------------------------------------------------------------------------------------------------------------------
4039
 * @fn dwt_readtempvbat()
4040
 *
4041
 * @brief this function reads the battery voltage and temperature of the MP
4042
 * The values read here will be the current values sampled by DW1000 AtoD converters.
4043
 * Note on Temperature: the temperature value needs to be converted to give the real temperature
4044
 * the formula is: 1.13 * reading - 113.0
4045
 * Note on Voltage: the voltage value needs to be converted to give the real voltage
4046
 * the formula is: 0.0057 * reading + 2.3
4047
 *
4048
 * NB: To correctly read the temperature this read should be done with xtal clock
4049
 * however that means that the receiver will be switched off, if receiver needs to be on then
4050
 * the timer is used to make sure the value is stable before reading
4051
 *
4052
 * input parameters:
4053
 * @param fastSPI - set to 1 if SPI rate > than 3MHz is used
4054
 *
4055
 * output parameters
4056
 *
4057
 * returns  (temp_raw<<8)|(vbat_raw)
4058
 */
4059
uint16_t dwt_readtempvbat(uint8_t fastSPI)
4060
{
4061
    uint8_t wr_buf[2];
4062
    uint8_t vbat_raw;
4063
    uint8_t temp_raw;
4064
4065
    // These writes should be single writes and in sequence
4066
    wr_buf[0] = 0x80; // Enable TLD Bias
4067
    dwt_writetodevice(RF_CONF_ID,0x11,1,wr_buf);
4068
4069
    wr_buf[0] = 0x0A; // Enable TLD Bias and ADC Bias
4070
    dwt_writetodevice(RF_CONF_ID,0x12,1,wr_buf);
4071
4072
    wr_buf[0] = 0x0f; // Enable Outputs (only after Biases are up and running)
4073
    dwt_writetodevice(RF_CONF_ID,0x12,1,wr_buf);    //
4074
4075
    // Reading All SAR inputs
4076
    wr_buf[0] = 0x00;
4077
    dwt_writetodevice(TX_CAL_ID, TC_SARL_SAR_C,1,wr_buf);
4078
    wr_buf[0] = 0x01; // Set SAR enable
4079
    dwt_writetodevice(TX_CAL_ID, TC_SARL_SAR_C,1,wr_buf);
4080
4081
    if(fastSPI == 1)
4082
    {
4083
        deca_sleep(1); // If using PLL clocks(and fast SPI rate) then this sleep is needed
4084
        // Read voltage and temperature.
4085
        dwt_readfromdevice(TX_CAL_ID, TC_SARL_SAR_LVBAT_OFFSET,2,wr_buf);
4086
    }
4087
    else //change to a slow clock
4088
    {
4089
        _dwt_enableclocks(FORCE_SYS_XTI); // NOTE: set system clock to XTI - this is necessary to make sure the values read are reliable
4090
        // Read voltage and temperature.
4091
        dwt_readfromdevice(TX_CAL_ID, TC_SARL_SAR_LVBAT_OFFSET,2,wr_buf);
4092
        // Default clocks (ENABLE_ALL_SEQ)
4093
        _dwt_enableclocks(ENABLE_ALL_SEQ); // Enable clocks for sequencing
4094
    }
4095
4096
    vbat_raw = wr_buf[0];
4097
    temp_raw = wr_buf[1];
4098
4099
    wr_buf[0] = 0x00; // Clear SAR enable
4100
    dwt_writetodevice(TX_CAL_ID, TC_SARL_SAR_C,1,wr_buf);
4101
4102
    return ((temp_raw<<8)|(vbat_raw));
4103
}
4104
4105
/*! ------------------------------------------------------------------------------------------------------------------
4106
 * @fn dwt_readwakeuptemp()
4107
 *
4108
 * @brief this function reads the temperature of the DW1000 that was sampled
4109
 * on waking from Sleep/Deepsleep. They are not current values, but read on last
4110
 * wakeup if DWT_TANDV bit is set in mode parameter of dwt_configuresleep
4111
 *
4112
 * input parameters:
4113
 *
4114
 * output parameters:
4115
 *
4116
 * returns: 8-bit raw temperature sensor value
4117
 */
4118
uint8_t dwt_readwakeuptemp(void)
4119
{
4120
    return dwt_read8bitoffsetreg(TX_CAL_ID, TC_SARL_SAR_LTEMP_OFFSET);
4121
}
4122
4123
/*! ------------------------------------------------------------------------------------------------------------------
4124
 * @fn dwt_readwakeupvbat()
4125
 *
4126
 * @brief this function reads the battery voltage of the DW1000 that was sampled
4127
 * on waking from Sleep/Deepsleep. They are not current values, but read on last
4128
 * wakeup if DWT_TANDV bit is set in mode parameter of dwt_configuresleep
4129
 *
4130
 * input parameters:
4131
 *
4132
 * output parameters:
4133
 *
4134
 * returns: 8-bit raw battery voltage sensor value
4135
 */
4136
uint8_t dwt_readwakeupvbat(void)
4137
{
4138
    return dwt_read8bitoffsetreg(TX_CAL_ID, TC_SARL_SAR_LVBAT_OFFSET);
4139
}
4140
4141
/*! ------------------------------------------------------------------------------------------------------------------
4142
 * @fn dwt_calcbandwidthtempadj()
4143
 *
4144
 * @brief this function determines the corrected bandwidth setting (PG_DELAY register setting)
4145
 * of the DW1000 which changes over temperature.
4146
 *
4147
 * input parameters:
4148
 * @param target_count - uint16_t - the PG count target to reach in order to correct the bandwidth
4149
 *
4150
 * output parameters:
4151
 *
4152
 * returns: (uint32) The setting to be programmed into the PG_DELAY value
4153
 */
4154
uint32_t dwt_calcbandwidthtempadj(uint16_t target_count)
4155
{
4156
    int i;
4157
    uint32_t bit_field, curr_bw;
4158
    int32_t delta_count = 0;
4159
    uint32_t best_bw = 0;
4160
    uint16_t raw_count = 0;
4161
    int32_t delta_lowest;
4162
4163
    // Used to store the current values of the registers so that they can be restored after
4164
    uint8_t old_pmsc_ctrl0;
4165
    uint16_t old_pmsc_ctrl1;
4166
    uint32_t old_rf_conf_txpow_mask;
4167
4168
    // Record the current values of these registers, to restore later
4169
    old_pmsc_ctrl0 = dwt_read8bitoffsetreg(PMSC_ID, PMSC_CTRL0_OFFSET);
4170
    old_pmsc_ctrl1 = dwt_read16bitoffsetreg(PMSC_ID, PMSC_CTRL1_OFFSET);
4171
    old_rf_conf_txpow_mask = dwt_read32bitreg(RF_CONF_ID);
4172
4173
    //  Set clock to XTAL
4174
    dwt_write8bitoffsetreg(PMSC_ID, PMSC_CTRL0_OFFSET, PMSC_CTRL0_SYSCLKS_19M);
4175
4176
    //  Disable sequencing
4177
    dwt_write16bitoffsetreg(PMSC_ID, PMSC_CTRL1_OFFSET, PMSC_CTRL1_PKTSEQ_DISABLE);
4178
4179
    //  Turn on CLK PLL, Mix Bias and PG
4180
    dwt_write32bitreg(RF_CONF_ID, RF_CONF_TXPOW_MASK | RF_CONF_PGMIXBIASEN_MASK);
4181
4182
    //  Set sys and TX clock to PLL
4183
    dwt_write8bitoffsetreg(PMSC_ID, PMSC_CTRL0_OFFSET, PMSC_CTRL0_SYSCLKS_125M | PMSC_CTRL0_TXCLKS_125M);
4184
4185
    // Set the MSB high for first guess
4186
    curr_bw = 0x80;
4187
    // Set starting bit
4188
    bit_field = 0x80;
4189
    // Initial lowest delta is the maximum difference that we should allow the count value to be from the target.
4190
    // If the algorithm is successful, it will be overwritten by a smaller value where the count value is closer
4191
    // to the target
4192
    delta_lowest = 300;
4193
4194
    for (i = 0; i < 7; i++)
4195
    {
4196
        // start with 0xc0 and test.
4197
        bit_field = bit_field >> 1;
4198
        curr_bw = curr_bw | bit_field;
4199
4200
        // Write bw setting to PG_DELAY register
4201
        dwt_write8bitoffsetreg(TX_CAL_ID, TC_PGDELAY_OFFSET, curr_bw);
4202
4203
        // Set cal direction and time
4204
        dwt_write8bitoffsetreg(TX_CAL_ID, TC_PGCCTRL_OFFSET, TC_PGCCTRL_DIR_CONV | TC_PGCCTRL_TMEAS_MASK);
4205
4206
        // Start cal
4207
        dwt_write8bitoffsetreg(TX_CAL_ID, TC_PGCCTRL_OFFSET, TC_PGCCTRL_DIR_CONV | TC_PGCCTRL_TMEAS_MASK | TC_PGCCTRL_CALSTART);
4208
        // Allow cal to complete
4209
        deca_sleep(100);
4210
4211
        // Read count value from the PG cal block
4212
        raw_count = dwt_read16bitoffsetreg(TX_CAL_ID, TC_PGCAL_STATUS_OFFSET) & TC_PGCAL_STATUS_DELAY_MASK;
4213
4214
        // lets keep track of the closest value to the target in case we overshoot
4215
        delta_count = abs((int)raw_count - (int)target_count);
4216
        if (delta_count < delta_lowest)
4217
        {
4218
            delta_lowest = delta_count;
4219
            best_bw = curr_bw;
4220
        }
4221
4222
        // Test the count results
4223
        if (raw_count > target_count)
4224
            // Count was lower, BW was lower so increase PG DELAY
4225
            curr_bw = curr_bw | bit_field;
4226
        else
4227
            // Count was higher
4228
            curr_bw = curr_bw & (~(bit_field));
4229
    }
4230
4231
    // Restore old register values
4232
    dwt_write8bitoffsetreg(PMSC_ID, PMSC_CTRL0_OFFSET, old_pmsc_ctrl0);
4233
    dwt_write16bitoffsetreg(PMSC_ID, PMSC_CTRL1_OFFSET, old_pmsc_ctrl1);
4234
    dwt_write32bitreg(RF_CONF_ID, old_rf_conf_txpow_mask);
4235
4236
    // Returns the best PG_DELAY setting
4237
    return best_bw;
4238
}
4239
4240
4241
/*! ------------------------------------------------------------------------------------------------------------------
4242
 * @fn _dwt_computetxpowersetting()
4243
 *
4244
 * @brief this function calculates the appropriate change to the TX_POWER register to compensate
4245
 * the TX power output at different temperatures.
4246
 *
4247
 * input parameters:
4248
 * @param ref_powerreg - uint32_t - the TX_POWER register value recorded when reference measurements were made
4249
 * @param power_adj - uint32_t - the adjustment in power level to be made, in 0.5dB steps
4250
 *
4251
 * output parameters:
4252
 *
4253
 * returns: (uint32) The setting to be programmed into the TX_POWER register
4254
 */
4255
uint32_t _dwt_computetxpowersetting(uint32_t ref_powerreg, int32_t power_adj)
4256
{
4257
    int32_t da_attn_change, mixer_gain_change;
4258
    uint8_t current_da_attn, current_mixer_gain;
4259
    uint8_t new_da_attn, new_mixer_gain;
4260
    uint32_t new_regval = 0;
4261
    int i;
4262
4263
    for(i = 0; i < 4; i++)
4264
    {
4265
        da_attn_change = 0;
4266
        mixer_gain_change = power_adj;
4267
        current_da_attn = ((ref_powerreg >> (i*8)) & 0xE0) >> 5;
4268
        current_mixer_gain = (ref_powerreg >> (i*8)) & 0x1F;
4269
4270
        // Mixer gain gives best performance between 4 and 20
4271
        while((current_mixer_gain + mixer_gain_change < 4) ||
4272
              (current_mixer_gain + mixer_gain_change > 20))
4273
        {
4274
            // If mixer gain goes outside bounds, adjust the DA attenuation to compensate
4275
            if(current_mixer_gain + mixer_gain_change > 20)
4276
            {
4277
                da_attn_change += 1;
4278
                mixer_gain_change -= (int) (DA_ATTN_STEP / MIXER_GAIN_STEP);
4279
            }
4280
            else if(current_mixer_gain + mixer_gain_change < 4)
4281
            {
4282
                da_attn_change += 1;
4283
                mixer_gain_change += (int) (DA_ATTN_STEP / MIXER_GAIN_STEP);
4284
            }
4285
        }
4286
4287
        new_da_attn = current_da_attn + da_attn_change;
4288
        new_mixer_gain = current_mixer_gain + mixer_gain_change;
4289
4290
        new_regval |= ((uint32_t) ((new_da_attn << 5) | new_mixer_gain)) << (i * 8);
4291
    }
4292
4293
    return (uint32_t)new_regval;
4294
}
4295
4296
/*! ------------------------------------------------------------------------------------------------------------------
4297
 * @fn dwt_calcpowertempadj()
4298
 *
4299
 * @brief this function determines the corrected power setting (TX_POWER setting) for the
4300
 * DW1000 which changes over temperature.
4301
 *
4302
 * input parameters:
4303
 * @param channel - uint8_t - the channel at which compensation of power level will be applied
4304
 * @param ref_powerreg - uint32_t - the TX_POWER register value recorded when reference measurements were made
4305
 * @param current_temperature - double - the current ambient temperature in degrees Celcius
4306
 * @param reference_temperature - double - the temperature at which reference measurements were made
4307
 * output parameters: None
4308
 *
4309
 * returns: (uint32) The corrected TX_POWER register value
4310
 */
4311
 uint32_t dwt_calcpowertempadj
4312
(
4313
       uint8_t channel,
4314
       uint32_t ref_powerreg,
4315
       double curr_temp,
4316
       double ref_temp
4317
)
4318
{
4319
    double delta_temp;
4320
    double delta_power;
4321
4322
    // Find the temperature differential
4323
    delta_temp = curr_temp - ref_temp;
4324
4325
    // Calculate the expected power differential at the current temperature
4326
    delta_power = delta_temp * txpwr_compensation[chan_idx[channel]];
4327
4328
    // Adjust the TX_POWER register value
4329
    return _dwt_computetxpowersetting(ref_powerreg, (int32_t)(delta_power / MIXER_GAIN_STEP));
4330
}
4331
4332
/*! ------------------------------------------------------------------------------------------------------------------
4333
 * @fn dwt_calcpgcount()
4334
 *
4335
 * @brief this function calculates the value in the pulse generator counter register (PGC_STATUS) for a given PG_DELAY
4336
 * This is used to take a reference measurement, and the value recorded as the reference is used to adjust the
4337
 * bandwidth of the device when the temperature changes.
4338
 *
4339
 * input parameters:
4340
 * @param pgdly - uint8_t - the PG_DELAY to set (to control bandwidth), and to find the corresponding count value for
4341
 * output parameters: None
4342
 *
4343
 * returns: (uint16) PGC_STATUS count value calculated from the provided PG_DELAY value - used as reference for later
4344
 * bandwidth adjustments
4345
 */
4346
uint16_t dwt_calcpgcount(uint8_t pgdly)
4347
{
4348
    // Perform PG count read ten times and take an average to smooth out any noise
4349
    const int NUM_SAMPLES = 10;
4350
    uint32_t sum_count = 0;
4351
    uint16_t average_count = 0, count = 0;
4352
    int i = 0;
4353
4354
    // Used to store the current values of the registers so that they can be restored after
4355
    uint8_t old_pmsc_ctrl0;
4356
    uint16_t old_pmsc_ctrl1;
4357
    uint32_t old_rf_conf_txpow_mask;
4358
4359
    // Record the current values of these registers, to restore later
4360
    old_pmsc_ctrl0 = dwt_read8bitoffsetreg(PMSC_ID, PMSC_CTRL0_OFFSET);
4361
    old_pmsc_ctrl1 = dwt_read16bitoffsetreg(PMSC_ID, PMSC_CTRL1_OFFSET);
4362
    old_rf_conf_txpow_mask = dwt_read32bitreg(RF_CONF_ID);
4363
4364
    //  Set clock to XTAL
4365
    dwt_write8bitoffsetreg(PMSC_ID, PMSC_CTRL0_OFFSET, PMSC_CTRL0_SYSCLKS_19M);
4366
    //  Disable sequencing
4367
    dwt_write16bitoffsetreg(PMSC_ID, PMSC_CTRL1_OFFSET, PMSC_CTRL1_PKTSEQ_DISABLE);
4368
    //  Turn on CLK PLL, Mix Bias and PG
4369
    dwt_write32bitreg(RF_CONF_ID, RF_CONF_TXPOW_MASK | RF_CONF_PGMIXBIASEN_MASK);
4370
    //  Set sys and TX clock to PLL
4371
    dwt_write8bitoffsetreg(PMSC_ID, PMSC_CTRL0_OFFSET, PMSC_CTRL0_SYSCLKS_125M | PMSC_CTRL0_TXCLKS_125M);
4372
4373
    for(i = 0; i < NUM_SAMPLES; i++) {
4374
        // Write bw setting to PG_DELAY register
4375
        dwt_write8bitoffsetreg(TX_CAL_ID, TC_PGDELAY_OFFSET, pgdly);
4376
4377
        // Set cal direction and time
4378
        dwt_write8bitoffsetreg(TX_CAL_ID, TC_PGCCTRL_OFFSET, TC_PGCCTRL_DIR_CONV | TC_PGCCTRL_TMEAS_MASK);
4379
4380
        // Start cal
4381
        dwt_write8bitoffsetreg(TX_CAL_ID, TC_PGCCTRL_OFFSET, TC_PGCCTRL_DIR_CONV | TC_PGCCTRL_TMEAS_MASK | TC_PGCCTRL_CALSTART);
4382
4383
        // Allow cal to complete - the TC_PGCCTRL_CALSTART bit will clear automatically
4384
        deca_sleep(100);
4385
4386
        // Read count value from the PG cal block
4387
        count = dwt_read16bitoffsetreg(TX_CAL_ID, TC_PGCAL_STATUS_OFFSET) & TC_PGCAL_STATUS_DELAY_MASK;
4388
4389
        sum_count += count;
4390
    }
4391
4392
     // Restore old register values
4393
    dwt_write8bitoffsetreg(PMSC_ID, PMSC_CTRL0_OFFSET, old_pmsc_ctrl0);
4394
    dwt_write16bitoffsetreg(PMSC_ID, PMSC_CTRL1_OFFSET, old_pmsc_ctrl1);
4395
    dwt_write32bitreg(RF_CONF_ID, old_rf_conf_txpow_mask);
4396
4397
    average_count = (int)(sum_count / NUM_SAMPLES);
4398
    return average_count;
4399
}
4400
4401
4402
/* ===============================================================================================
4403
   List of expected (known) device ID handled by this software
4404
   ===============================================================================================
4405

4406
    0xDECA0130                               // DW1000 - MP
4407

4408
   ===============================================================================================
4409
*/
4410
4411
/****************************************************************************************************************************************************
4412
 *
4413
 * Declaration of platform-dependent lower level functions.
4414
 *
4415
 ****************************************************************************************************************************************************/
4416
4417 33f54213 Cung Sang
/****************************************************************************//**
4418
 *
4419
 *         alld_dw1000.c                                        SPI Section
4420
 *
4421
 *******************************************************************************/
4422 69a601a5 Cung Sang
4423
/*! ------------------------------------------------------------------------------------------------------------------
4424
 * Function: writetospi()
4425
 *
4426
 * Low level abstract function for DW1000 to write to the SPI
4427
 * Takes two separate byte buffers for write header and write data
4428
 * returns 0 for success, or -1 for error
4429
 */
4430
#pragma GCC optimize ("O3")
4431 33f54213 Cung Sang
static int writetospi(uint16_t headerLength,
4432 69a601a5 Cung Sang
               const        uint8_t *headerBuffer,
4433
               uint32_t bodyLength,
4434
               const        uint8_t *bodyBuffer)
4435
{
4436
4437
    uint8_t buffer[bodyLength + 3];
4438
    memcpy(buffer, headerBuffer, headerLength); //copy data to buffer
4439
    memcpy(&buffer[headerLength], bodyBuffer, bodyLength); //copy data to buffer
4440
4441 4172c48d Cung Sang
    apalSPITransmit(pdw1000local->driver->spid,
4442 69a601a5 Cung Sang
                    buffer,
4443
                    bodyLength + headerLength); // send header and data
4444
4445
    return 0;
4446
} // end writetospi()
4447
4448
4449
/*! ------------------------------------------------------------------------------------------------------------------
4450
 * Function: readfromspi()
4451
 *
4452
 * Low level abstract function for DW1000 to read from the SPI
4453
 * Takes two separate byte buffers for write header and read data
4454
 * returns the offset into read buffer where first byte of read data may be found,
4455
 * or returns -1 if there was an error
4456
 */
4457
#pragma GCC optimize ("O3")
4458 33f54213 Cung Sang
static int readfromspi(uint16_t headerLength,
4459 69a601a5 Cung Sang
                const uint8_t *headerBuffer,
4460
                uint32_t readlength,
4461
                uint8_t *readBuffer)
4462
{
4463
4464 4172c48d Cung Sang
    apalSPITransmitAndReceive(pdw1000local->driver->spid,
4465 69a601a5 Cung Sang
                              headerBuffer,
4466
                              readBuffer,
4467
                              headerLength,
4468
                              readlength);
4469
4470
    return 0;
4471
} // end readfromspi()
4472
4473
/****************************************************************************//**
4474
 *
4475
 *         alld_dw1000.c                                        IRQ section
4476
 *
4477
 *******************************************************************************/
4478
4479
4480
/*! ------------------------------------------------------------------------------------------------------------------
4481
 * Function: decamutexon()
4482
 *
4483
 * Description: This function should disable interrupts. This is called at the start of a critical section
4484
 * It returns the irq state before disable, this value is used to re-enable in decamutexoff call
4485
 *
4486
 * Note: The body of this function is platform specific
4487
 *
4488
 * input parameters:        
4489
 *
4490
 * output parameters
4491
 *
4492
 * returns the state of the DW1000 interrupt
4493
 */
4494 33f54213 Cung Sang
decaIrqStatus_t decamutexon(void)
4495 69a601a5 Cung Sang
{
4496
4497 33f54213 Cung Sang
  decaIrqStatus_t s = port_GetEXT_IRQStatus();
4498
  if(s) {
4499
    port_DisableEXT_IRQ(); //disable the external interrupt line
4500
  }
4501
  return s ;   // return state before disable, value is used to re-enable in decamutexoff call
4502 69a601a5 Cung Sang
}
4503
4504
/*! ------------------------------------------------------------------------------------------------------------------
4505
 * Function: decamutexoff()
4506
 *
4507
 * Description: This function should re-enable interrupts, or at least restore their state as returned(&saved) by decamutexon 
4508
 * This is called at the end of a critical section
4509
 *
4510
 * Note: The body of this function is platform specific
4511
 *
4512
 * input parameters:        
4513
 * @param s - the state of the DW1000 interrupt as returned by decamutexon
4514
 *
4515
 * output parameters
4516
 *
4517
 * returns the state of the DW1000 interrupt
4518
 */
4519
void decamutexoff(decaIrqStatus_t s)
4520
{
4521 33f54213 Cung Sang
//  (void) s;
4522
  if(s) { //need to check the port state as we can't use level sensitive interrupt on the STM ARM
4523
    port_EnableEXT_IRQ();
4524
  }
4525
  return;
4526 69a601a5 Cung Sang
}
4527
4528
4529
/*! Wrapper function to be used by decadriver. Declared in deca_device_api.h 
4530
 *
4531
 */
4532
4533 4172c48d Cung Sang
/*! @brief sleep or idle the thread in millisecond */
4534 69a601a5 Cung Sang
void deca_sleep(unsigned int time_ms)
4535
{
4536 33f54213 Cung Sang
  aosThdMSleep(time_ms);
4537 69a601a5 Cung Sang
}
4538
4539 4172c48d Cung Sang
/*! @brief sleep or idle the thread in millisecond */
4540 69a601a5 Cung Sang
void Sleep(unsigned int time_ms)
4541
{
4542 33f54213 Cung Sang
  aosThdMSleep(time_ms);
4543 69a601a5 Cung Sang
}
4544
4545
4546
void port_wakeup_dw1000_fast(){ // NOT SUPPORTED
4547 33f54213 Cung Sang
  return;
4548 69a601a5 Cung Sang
}
4549
4550 4172c48d Cung Sang
/*! @brief Get the current system tick time */
4551 69a601a5 Cung Sang
uint32_t portGetTickCnt(){
4552 33f54213 Cung Sang
  return chVTGetSystemTimeX();
4553 69a601a5 Cung Sang
}
4554
4555
//inline uint32_t portGetTickCnt(){
4556
//    return (uint32_t) chVTGetSystemTimeX();
4557
//}
4558
4559
4560 4172c48d Cung Sang
/*! @brief Disable the interrupt handler */
4561 69a601a5 Cung Sang
void port_DisableEXT_IRQ(void){   
4562 33f54213 Cung Sang
  nvicDisableVector(DW1000_EXTI_IRQn);
4563 69a601a5 Cung Sang
4564
}
4565
4566 4172c48d Cung Sang
/*! @brief Enable the interrupt handler */
4567 69a601a5 Cung Sang
void port_EnableEXT_IRQ(void){    
4568 33f54213 Cung Sang
  nvicEnableVector(DW1000_EXTI_IRQn, STM32_IRQ_EXTI10_15_PRIORITY);
4569 69a601a5 Cung Sang
}
4570
4571 4172c48d Cung Sang
/*! @brief Get the current status of the interrupt handler */
4572 33f54213 Cung Sang
decaIrqStatus_t port_GetEXT_IRQStatus(void){
4573
  decaIrqStatus_t bitstatus = RESET;
4574 69a601a5 Cung Sang
4575
  if(NVIC_GetActive(DW1000_EXTI_IRQn)|| NVIC_GetPendingIRQ(DW1000_EXTI_IRQn)){
4576
    bitstatus = SET; //Interrupt is active or panding
4577
  }
4578
  else {
4579 33f54213 Cung Sang
    bitstatus = RESET; //No interrupt IRQ at the moment
4580 69a601a5 Cung Sang
  }
4581
4582
  return bitstatus;
4583
}
4584
4585
#endif /* defined(AMIROLLD_CFG_DW1000) && (AMIROLLD_CFG_DW1000 == 1) */