Statistics
| Branch: | Tag: | Revision:

amiro-lld / source / DW1000 / v1 / alld_dw1000_v1.c @ 1473a57f

History | View | Annotate | Download (151.037 KB)

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

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

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

15
You should have received a copy of the GNU Lesser General Public License
16
along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
*/
18

    
19
/*! ------------------------------------------------------------------------------------------------------------------
20
 * @file    deca_device.c
21
 * @brief   Decawave device configuration and control functions
22
 *
23
 * @attention
24
 *
25
 * Copyright 2013 (c) Decawave Ltd, Dublin, Ireland.
26
 *
27
 * All rights reserved.
28
 *
29
 */
30

    
31
#include <alld_DW1000.h>
32
#if (defined(AMIROLLD_CFG_DW1000) && (AMIROLLD_CFG_DW1000 == 1)) || defined(__DOXYGEN__)
33

    
34
#include <v1/alld_dw1000_regs_v1.h>
35
#include <assert.h>
36
#include <string.h>
37
#include <stdlib.h>
38
#include <math.h>
39

    
40

    
41
// 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
// 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
    int rangeint25cm = (int) ((double)range * 4.00) ;       // convert range to integer number of 25cm values.
868

    
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
    mOffset = (double) cmoffseti ;                                       // offset result in centimmetres
914

    
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
int32_t _dwt_otpprogword32(uint32_t data, uint16_t address);
936
// 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
int dwt_initialise(const uint16_t config, DW1000Driver* drv)
1004
{
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
    pdw1000local->driver = drv;
1018

    
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
    pdw1000local->sysCFGreg |= (SYS_CFG_PHR_MODE_11 & (uint32_t)(config->phrMode << SYS_CFG_PHR_MODE_SHFT));
1339

    
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
    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

    
1413
    dwt_write32bitreg(CHAN_CTRL_ID,regval) ;
1414

    
1415
    // Set up TX Preamble Size, PRF and Data Rate
1416
    pdw1000local->txFCTRL = (uint32_t)(((config->txPreambLength | config->prf) << TX_FCTRL_TXPRF_SHFT) | (config->dataRate << TX_FCTRL_TXBR_SHFT));
1417
    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()