Statistics
| Branch: | Tag: | Revision:

amiro-lld / source / DW1000 / v1 / alld_dw1000_v1.c @ 54dbb62d

History | View | Annotate | Download (151.037 KB)

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

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

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

4395
    0xDECA0130                               // DW1000 - MP
4396

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