|
1 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
2 |
* @file deca_device.c
|
|
3 |
* @brief Decawave device configuration and control functions
|
|
4 |
*
|
|
5 |
* @attention
|
|
6 |
*
|
|
7 |
* Copyright 2013 (c) Decawave Ltd, Dublin, Ireland.
|
|
8 |
*
|
|
9 |
* All rights reserved.
|
|
10 |
*
|
|
11 |
*/
|
|
12 |
|
|
13 |
#include <assert.h>
|
|
14 |
#include <stdlib.h>
|
|
15 |
|
|
16 |
#include "deca_types.h"
|
|
17 |
#include "deca_param_types.h"
|
|
18 |
#include "deca_regs.h"
|
|
19 |
#include "deca_device_api.h"
|
|
20 |
|
|
21 |
// Defines for enable_clocks function
|
|
22 |
#define FORCE_SYS_XTI 0
|
|
23 |
#define ENABLE_ALL_SEQ 1
|
|
24 |
#define FORCE_SYS_PLL 2
|
|
25 |
#define READ_ACC_ON 7
|
|
26 |
#define READ_ACC_OFF 8
|
|
27 |
#define FORCE_OTP_ON 11
|
|
28 |
#define FORCE_OTP_OFF 12
|
|
29 |
#define FORCE_TX_PLL 13
|
|
30 |
#define FORCE_LDE 14
|
|
31 |
|
|
32 |
// Defines for ACK request bitmask in DATA and MAC COMMAND frame control (first byte) - Used to detect AAT bit wrongly set.
|
|
33 |
#define FCTRL_ACK_REQ_MASK 0x20
|
|
34 |
// Frame control maximum length in bytes.
|
|
35 |
#define FCTRL_LEN_MAX 2
|
|
36 |
|
|
37 |
// #define DWT_API_ERROR_CHECK // define so API checks config input parameters
|
|
38 |
|
|
39 |
// -------------------------------------------------------------------------------------------------------------------
|
|
40 |
//
|
|
41 |
// Internal functions for controlling and configuring the device
|
|
42 |
//
|
|
43 |
// -------------------------------------------------------------------------------------------------------------------
|
|
44 |
|
|
45 |
// Enable and Configure specified clocks
|
|
46 |
void _dwt_enableclocks(int clocks) ;
|
|
47 |
// Configure the ucode (FP algorithm) parameters
|
|
48 |
void _dwt_configlde(int prf);
|
|
49 |
// Load ucode from OTP/ROM
|
|
50 |
void _dwt_loaducodefromrom(void);
|
|
51 |
// Read non-volatile memory
|
|
52 |
uint32 _dwt_otpread(uint16 address);
|
|
53 |
// Program the non-volatile memory
|
|
54 |
uint32 _dwt_otpprogword32(uint32 data, uint16 address);
|
|
55 |
// Upload the device configuration into always on memory
|
|
56 |
void _dwt_aonarrayupload(void);
|
|
57 |
// -------------------------------------------------------------------------------------------------------------------
|
|
58 |
|
|
59 |
/*!
|
|
60 |
* Static data for DW1000 DecaWave Transceiver control
|
|
61 |
*/
|
|
62 |
|
|
63 |
// -------------------------------------------------------------------------------------------------------------------
|
|
64 |
// Structure to hold device data
|
|
65 |
typedef struct
|
|
66 |
{
|
|
67 |
uint32 partID ; // IC Part ID - read during initialisation
|
|
68 |
uint32 lotID ; // IC Lot ID - read during initialisation
|
|
69 |
uint8 vBatP ; // IC V bat read during production and stored in OTP (Vmeas @ 3V3)
|
|
70 |
uint8 tempP ; // IC V temp read during production and stored in OTP (Tmeas @ 23C)
|
|
71 |
uint8 longFrames ; // Flag in non-standard long frame mode
|
|
72 |
uint8 otprev ; // OTP revision number (read during initialisation)
|
|
73 |
uint32 txFCTRL ; // Keep TX_FCTRL register config
|
|
74 |
uint32 sysCFGreg ; // Local copy of system config register
|
|
75 |
uint8 dblbuffon; // Double RX buffer mode flag
|
|
76 |
uint8 wait4resp ; // wait4response was set with last TX start command
|
|
77 |
uint16 sleep_mode; // Used for automatic reloading of LDO tune and microcode at wake-up
|
|
78 |
uint16 otp_mask ; // Local copy of the OTP mask used in dwt_initialise call
|
|
79 |
dwt_cb_data_t cbData; // Callback data structure
|
|
80 |
dwt_cb_t cbTxDone; // Callback for TX confirmation event
|
|
81 |
dwt_cb_t cbRxOk; // Callback for RX good frame event
|
|
82 |
dwt_cb_t cbRxTo; // Callback for RX timeout events
|
|
83 |
dwt_cb_t cbRxErr; // Callback for RX error events
|
|
84 |
} dwt_local_data_t ;
|
|
85 |
|
|
86 |
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
|
|
87 |
static dwt_local_data_t *pdw1000local = dw1000local ; // Static local data structure pointer
|
|
88 |
|
|
89 |
|
|
90 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
91 |
* @fn dwt_apiversion()
|
|
92 |
*
|
|
93 |
* @brief This function returns the version of the API as defined by DW1000_DRIVER_VERSION
|
|
94 |
*
|
|
95 |
* input parameters
|
|
96 |
*
|
|
97 |
* output parameters
|
|
98 |
*
|
|
99 |
* returns version (DW1000_DRIVER_VERSION)
|
|
100 |
*/
|
|
101 |
int32 dwt_apiversion(void)
|
|
102 |
{
|
|
103 |
return DW1000_DRIVER_VERSION ;
|
|
104 |
}
|
|
105 |
|
|
106 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
107 |
* @fn dwt_setlocaldataptr()
|
|
108 |
*
|
|
109 |
* @brief This function sets the local data structure pointer to point to the element in the local array as given by the index.
|
|
110 |
*
|
|
111 |
* input parameters
|
|
112 |
* @param index - selects the array element to point to. Must be within the array bounds, i.e. < DWT_NUM_DW_DEV
|
|
113 |
*
|
|
114 |
* output parameters
|
|
115 |
*
|
|
116 |
* returns DWT_SUCCESS for success, or DWT_ERROR for error
|
|
117 |
*/
|
|
118 |
int dwt_setlocaldataptr(unsigned int index)
|
|
119 |
{
|
|
120 |
// Check the index is within the array bounds
|
|
121 |
if (DWT_NUM_DW_DEV <= index) // return error if index outside the array bounds
|
|
122 |
{
|
|
123 |
return DWT_ERROR ;
|
|
124 |
}
|
|
125 |
|
|
126 |
pdw1000local = &dw1000local[index];
|
|
127 |
|
|
128 |
return DWT_SUCCESS ;
|
|
129 |
}
|
|
130 |
|
|
131 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
132 |
* @fn dwt_initialise()
|
|
133 |
*
|
|
134 |
* @brief This function initiates communications with the DW1000 transceiver
|
|
135 |
* and reads its DEV_ID register (address 0x00) to verify the IC is one supported
|
|
136 |
* by this software (e.g. DW1000 32-bit device ID value is 0xDECA0130). Then it
|
|
137 |
* does any initial once only device configurations needed for its use and initialises
|
|
138 |
* as necessary any static data items belonging to this low-level driver.
|
|
139 |
*
|
|
140 |
* This function does not need to be called after DW1000 device is woken up from DEEPSLEEP,
|
|
141 |
* the device will preserve register values e.g. LDO, UCODE, XTAL. However if needed this
|
|
142 |
* function can be called to initialise internal structure dw1000local[] if it has not been preserved
|
|
143 |
* (e.g. if micro was in sleep and its RAM data (containing dw1000local structure was not preserved during sleep)
|
|
144 |
*
|
|
145 |
* NOTES:
|
|
146 |
* 1. When DW1000 is powered on this function needs to be run before dwt_configuresleep,
|
|
147 |
* also the SPI frequency has to be < 3MHz
|
|
148 |
* 2. It reads and applies LDO tune and crystal trim values from OTP memory
|
|
149 |
* 3. If accurate RX timestamping is needed microcode/LDE must be loaded
|
|
150 |
*
|
|
151 |
* input parameters
|
|
152 |
* @param config - specifies what configuration to load
|
|
153 |
* DWT_LOADNONE 0x00 - do not load any values from OTP memory
|
|
154 |
* DWT_LOADUCODE 0x01 - load the LDE microcode from ROM - enable accurate RX timestamp
|
|
155 |
* DWT_DW_WAKE_UP 0x02 - just initialise dw1000local[] values (e.g. DW1000 has woken up)
|
|
156 |
* DWT_DW_WUP_NO_UCODE 0x04 - if microcode/LDE algorithm has not already been loaded (on power up) e.g. when LDE is not used
|
|
157 |
* DWT_READ_OTP_PID 0x10 - read part ID from OTP
|
|
158 |
* DWT_READ_OTP_LID 0x20 - read lot ID from OTP
|
|
159 |
* DWT_READ_OTP_BAT 0x40 - read ref voltage from OTP
|
|
160 |
* DWT_READ_OTP_TMP 0x80 - read ref temperature from OTP
|
|
161 |
* output parameters
|
|
162 |
*
|
|
163 |
* returns DWT_SUCCESS for success, or DWT_ERROR for error
|
|
164 |
*/
|
|
165 |
// OTP addresses definitions
|
|
166 |
#define LDOTUNE_ADDRESS (0x04)
|
|
167 |
#define PARTID_ADDRESS (0x06)
|
|
168 |
#define LOTID_ADDRESS (0x07)
|
|
169 |
#define VBAT_ADDRESS (0x08)
|
|
170 |
#define VTEMP_ADDRESS (0x09)
|
|
171 |
#define XTRIM_ADDRESS (0x1E)
|
|
172 |
|
|
173 |
int dwt_initialise(int config)
|
|
174 |
{
|
|
175 |
uint16 otp_xtaltrim_and_rev = 0;
|
|
176 |
uint32 ldo_tune = 0;
|
|
177 |
|
|
178 |
pdw1000local->dblbuffon = 0; // - set to 0 - meaning double buffer mode is off by default
|
|
179 |
pdw1000local->wait4resp = 0; // - set to 0 - meaning wait for response not active
|
|
180 |
pdw1000local->sleep_mode = 0; // - set to 0 - meaning sleep mode has not been configured
|
|
181 |
|
|
182 |
pdw1000local->cbTxDone = NULL;
|
|
183 |
pdw1000local->cbRxOk = NULL;
|
|
184 |
pdw1000local->cbRxTo = NULL;
|
|
185 |
pdw1000local->cbRxErr = NULL;
|
|
186 |
|
|
187 |
#if DWT_API_ERROR_CHECK
|
|
188 |
pdw1000local->otp_mask = config ; // Save the READ_OTP config mask
|
|
189 |
#endif
|
|
190 |
|
|
191 |
// Read and validate device ID, return -1 if not recognised
|
|
192 |
if (DWT_DEVICE_ID != dwt_readdevid()) // MP IC ONLY (i.e. DW1000) FOR THIS CODE
|
|
193 |
{
|
|
194 |
return DWT_ERROR ;
|
|
195 |
}
|
|
196 |
|
|
197 |
if(!(DWT_DW_WAKE_UP & config)) // Don't reset the device if DWT_DW_WAKE_UP bit is set, e.g. when calling this API after wake up
|
|
198 |
{
|
|
199 |
dwt_softreset(); // Make sure the device is completely reset before starting initialisation
|
|
200 |
}
|
|
201 |
|
|
202 |
if(!((DWT_DW_WAKE_UP & config) && ((DWT_READ_OTP_TMP | DWT_READ_OTP_BAT | DWT_READ_OTP_LID | DWT_READ_OTP_PID | DWT_DW_WUP_RD_OTPREV)& config)))
|
|
203 |
{
|
|
204 |
_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
|
|
205 |
} // when not reading from OTP, clocks don't need to change.
|
|
206 |
|
|
207 |
// Configure the CPLL lock detect
|
|
208 |
dwt_write8bitoffsetreg(EXT_SYNC_ID, EC_CTRL_OFFSET, EC_CTRL_PLLLCK);
|
|
209 |
|
|
210 |
// When DW1000 IC is initialised from power up, then the LDO value should be kicked from OTP, otherwise if this API is called after
|
|
211 |
// DW1000 IC has been woken up (DWT_DW_WAKE_UP bit is set) this can be skipped as LDO would have already been automatically
|
|
212 |
// kicked/loaded on wake up
|
|
213 |
if(!(DWT_DW_WAKE_UP & config))
|
|
214 |
{
|
|
215 |
// Load LDO tune from OTP and kick it if there is a value actually programmed.
|
|
216 |
ldo_tune = _dwt_otpread(LDOTUNE_ADDRESS);
|
|
217 |
if((ldo_tune & 0xFF) != 0)
|
|
218 |
{
|
|
219 |
// Kick LDO tune
|
|
220 |
dwt_write8bitoffsetreg(OTP_IF_ID, OTP_SF, OTP_SF_LDO_KICK); // Set load LDO kick bit
|
|
221 |
pdw1000local->sleep_mode |= AON_WCFG_ONW_LLDO; // LDO tune must be kicked at wake-up
|
|
222 |
}
|
|
223 |
}
|
|
224 |
else
|
|
225 |
{ //if LDOTUNE reg contains value different from default it means it was kicked from OTP and thus set AON_WCFG_ONW_LLDO.
|
|
226 |
if(dwt_read32bitoffsetreg(RF_CONF_ID, LDOTUNE) != LDOTUNE_DEFAULT)
|
|
227 |
pdw1000local->sleep_mode |= AON_WCFG_ONW_LLDO;
|
|
228 |
}
|
|
229 |
|
|
230 |
if((!(DWT_DW_WAKE_UP & config)) || ((DWT_DW_WAKE_UP & config) && (DWT_DW_WUP_RD_OTPREV & config)))
|
|
231 |
{
|
|
232 |
// Read OTP revision number
|
|
233 |
otp_xtaltrim_and_rev = _dwt_otpread(XTRIM_ADDRESS) & 0xffff; // Read 32 bit value, XTAL trim val is in low octet-0 (5 bits)
|
|
234 |
pdw1000local->otprev = (otp_xtaltrim_and_rev >> 8) & 0xff; // OTP revision is the next byte
|
|
235 |
}
|
|
236 |
else
|
|
237 |
pdw1000local->otprev = 0; // If OTP valuse are not used, if this API is called after DW1000 IC has been woken up
|
|
238 |
// (DWT_DW_WAKE_UP bit is set), set otprev to 0
|
|
239 |
|
|
240 |
if(!(DWT_DW_WAKE_UP & config))
|
|
241 |
{
|
|
242 |
// 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
|
|
243 |
if ((otp_xtaltrim_and_rev & 0x1F) == 0) // A value of 0 means that the crystal has not been trimmed
|
|
244 |
{
|
|
245 |
otp_xtaltrim_and_rev = FS_XTALT_MIDRANGE ; // Set to mid-range if no calibration value inside
|
|
246 |
}
|
|
247 |
// Configure XTAL trim
|
|
248 |
dwt_setxtaltrim((uint8)otp_xtaltrim_and_rev);
|
|
249 |
}
|
|
250 |
|
|
251 |
if(DWT_READ_OTP_PID & config)
|
|
252 |
{
|
|
253 |
// Load Part from OTP
|
|
254 |
pdw1000local->partID = _dwt_otpread(PARTID_ADDRESS);
|
|
255 |
}
|
|
256 |
else
|
|
257 |
{
|
|
258 |
pdw1000local->partID = 0;
|
|
259 |
}
|
|
260 |
|
|
261 |
if(DWT_READ_OTP_LID & config)
|
|
262 |
{
|
|
263 |
// Load Lot ID from OTP
|
|
264 |
pdw1000local->lotID = _dwt_otpread(LOTID_ADDRESS);
|
|
265 |
}
|
|
266 |
else
|
|
267 |
{
|
|
268 |
pdw1000local->lotID = 0;
|
|
269 |
}
|
|
270 |
|
|
271 |
if(DWT_READ_OTP_BAT & config)
|
|
272 |
{
|
|
273 |
// Load VBAT from OTP
|
|
274 |
pdw1000local->vBatP = _dwt_otpread(VBAT_ADDRESS) & 0xff;
|
|
275 |
}
|
|
276 |
else
|
|
277 |
{
|
|
278 |
pdw1000local->vBatP = 0;
|
|
279 |
}
|
|
280 |
|
|
281 |
if(DWT_READ_OTP_TMP & config)
|
|
282 |
{
|
|
283 |
// Load TEMP from OTP
|
|
284 |
pdw1000local->tempP = _dwt_otpread(VTEMP_ADDRESS) & 0xff;
|
|
285 |
}
|
|
286 |
else
|
|
287 |
{
|
|
288 |
pdw1000local->tempP = 0;
|
|
289 |
}
|
|
290 |
|
|
291 |
// Load leading edge detect code (LDE/microcode)
|
|
292 |
if(!(DWT_DW_WAKE_UP & config))
|
|
293 |
{
|
|
294 |
if(DWT_LOADUCODE & config)
|
|
295 |
{
|
|
296 |
_dwt_loaducodefromrom();
|
|
297 |
pdw1000local->sleep_mode |= AON_WCFG_ONW_LLDE; // microcode must be loaded at wake-up if loaded on initialisation
|
|
298 |
}
|
|
299 |
else // Should disable the LDERUN bit enable if LDE has not been loaded
|
|
300 |
{
|
|
301 |
uint16 rega = dwt_read16bitoffsetreg(PMSC_ID, PMSC_CTRL1_OFFSET+1) ;
|
|
302 |
rega &= 0xFDFF ; // Clear LDERUN bit
|
|
303 |
dwt_write16bitoffsetreg(PMSC_ID, PMSC_CTRL1_OFFSET+1, rega) ;
|
|
304 |
}
|
|
305 |
}
|
|
306 |
else //if DWT_DW_WUP_NO_UCODE is set then assume that the UCODE was loaded from ROM (i.e. DWT_LOADUCODE was set on power up),
|
|
307 |
{ //thus set AON_WCFG_ONW_LLDE, otherwise don't set the AON_WCFG_ONW_LLDE bit in the sleep_mode configuration
|
|
308 |
if((DWT_DW_WUP_NO_UCODE & config) == 0)
|
|
309 |
{
|
|
310 |
pdw1000local->sleep_mode |= AON_WCFG_ONW_LLDE;
|
|
311 |
}
|
|
312 |
}
|
|
313 |
|
|
314 |
_dwt_enableclocks(ENABLE_ALL_SEQ); // Enable clocks for sequencing
|
|
315 |
|
|
316 |
// The 3 bits in AON CFG1 register must be cleared to ensure proper operation of the DW1000 in DEEPSLEEP mode.
|
|
317 |
dwt_write8bitoffsetreg(AON_ID, AON_CFG1_OFFSET, 0x00);
|
|
318 |
|
|
319 |
// Read system register / store local copy
|
|
320 |
pdw1000local->sysCFGreg = dwt_read32bitreg(SYS_CFG_ID) ; // Read sysconfig register
|
|
321 |
pdw1000local->longFrames = (pdw1000local->sysCFGreg & SYS_CFG_PHR_MODE_11) >> SYS_CFG_PHR_MODE_SHFT ; //configure longFrames
|
|
322 |
|
|
323 |
pdw1000local->txFCTRL = dwt_read32bitreg(TX_FCTRL_ID) ;
|
|
324 |
|
|
325 |
return DWT_SUCCESS ;
|
|
326 |
|
|
327 |
} // end dwt_initialise()
|
|
328 |
|
|
329 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
330 |
* @fn dwt_otprevision()
|
|
331 |
*
|
|
332 |
* @brief This is used to return the read OTP revision
|
|
333 |
*
|
|
334 |
* NOTE: dwt_initialise() must be called prior to this function so that it can return a relevant value.
|
|
335 |
*
|
|
336 |
* input parameters
|
|
337 |
*
|
|
338 |
* output parameters
|
|
339 |
*
|
|
340 |
* returns the read OTP revision value
|
|
341 |
*/
|
|
342 |
uint8 dwt_otprevision(void)
|
|
343 |
{
|
|
344 |
return pdw1000local->otprev ;
|
|
345 |
}
|
|
346 |
|
|
347 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
348 |
* @fn dwt_setfinegraintxseq()
|
|
349 |
*
|
|
350 |
* @brief This function enables/disables the fine grain TX sequencing (enabled by default).
|
|
351 |
*
|
|
352 |
* input parameters
|
|
353 |
* @param enable - 1 to enable fine grain TX sequencing, 0 to disable it.
|
|
354 |
*
|
|
355 |
* output parameters none
|
|
356 |
*
|
|
357 |
* no return value
|
|
358 |
*/
|
|
359 |
void dwt_setfinegraintxseq(int enable)
|
|
360 |
{
|
|
361 |
if (enable)
|
|
362 |
{
|
|
363 |
dwt_write16bitoffsetreg(PMSC_ID, PMSC_TXFINESEQ_OFFSET, PMSC_TXFINESEQ_ENABLE);
|
|
364 |
}
|
|
365 |
else
|
|
366 |
{
|
|
367 |
dwt_write16bitoffsetreg(PMSC_ID, PMSC_TXFINESEQ_OFFSET, PMSC_TXFINESEQ_DISABLE);
|
|
368 |
}
|
|
369 |
}
|
|
370 |
|
|
371 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
372 |
* @fn dwt_setlnapamode()
|
|
373 |
*
|
|
374 |
* @brief This is used to enable GPIO for external LNA or PA functionality - HW dependent, consult the DW1000 User Manual.
|
|
375 |
* This can also be used for debug as enabling TX and RX GPIOs is quite handy to monitor DW1000's activity.
|
|
376 |
*
|
|
377 |
* NOTE: Enabling PA functionality requires that fine grain TX sequencing is deactivated. This can be done using
|
|
378 |
* dwt_setfinegraintxseq().
|
|
379 |
*
|
|
380 |
* input parameters
|
|
381 |
* @param lna_pa - bit field: bit 0 if set will enable LNA functionality,
|
|
382 |
* : bit 1 if set will enable PA functionality,
|
|
383 |
* : to disable LNA/PA set the bits to 0
|
|
384 |
*
|
|
385 |
* no return value
|
|
386 |
*/
|
|
387 |
void dwt_setlnapamode(int lna_pa)
|
|
388 |
{
|
|
389 |
uint32 gpio_mode = dwt_read32bitoffsetreg(GPIO_CTRL_ID, GPIO_MODE_OFFSET);
|
|
390 |
gpio_mode &= ~(GPIO_MSGP4_MASK | GPIO_MSGP5_MASK | GPIO_MSGP6_MASK);
|
|
391 |
if (lna_pa & DWT_LNA_ENABLE)
|
|
392 |
{
|
|
393 |
gpio_mode |= GPIO_PIN6_EXTRXE;
|
|
394 |
}
|
|
395 |
if (lna_pa & DWT_PA_ENABLE)
|
|
396 |
{
|
|
397 |
gpio_mode |= (GPIO_PIN5_EXTTXE | GPIO_PIN4_EXTPA);
|
|
398 |
}
|
|
399 |
dwt_write32bitoffsetreg(GPIO_CTRL_ID, GPIO_MODE_OFFSET, gpio_mode);
|
|
400 |
}
|
|
401 |
|
|
402 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
403 |
* @fn dwt_enablegpioclocks()
|
|
404 |
*
|
|
405 |
* @brief This is used to enable GPIO clocks. The clocks are needed to ensure correct GPIO operation
|
|
406 |
*
|
|
407 |
* input parameters
|
|
408 |
*
|
|
409 |
* output parameters
|
|
410 |
*
|
|
411 |
* no return value
|
|
412 |
*/
|
|
413 |
void dwt_enablegpioclocks(void)
|
|
414 |
{
|
|
415 |
uint32 pmsc_clock_ctrl = dwt_read32bitreg(PMSC_ID);
|
|
416 |
dwt_write32bitreg(PMSC_ID, pmsc_clock_ctrl | PMSC_CTRL0_GPCE | PMSC_CTRL0_GPRN) ;
|
|
417 |
}
|
|
418 |
|
|
419 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
420 |
* @fn dwt_setgpiodirection()
|
|
421 |
*
|
|
422 |
* @brief This is used to set GPIO direction as an input (1) or output (0)
|
|
423 |
*
|
|
424 |
* input parameters
|
|
425 |
* @param gpioNum - this is the GPIO to configure - see GxM0... GxM8 in the deca_regs.h file
|
|
426 |
* @param direction - this sets the GPIO direction - see GxP0... GxP8 in the deca_regs.h file
|
|
427 |
*
|
|
428 |
* output parameters
|
|
429 |
*
|
|
430 |
* no return value
|
|
431 |
*/
|
|
432 |
void dwt_setgpiodirection(uint32 gpioNum, uint32 direction)
|
|
433 |
{
|
|
434 |
uint8 buf[GPIO_DIR_LEN];
|
|
435 |
uint32 command = direction | gpioNum;
|
|
436 |
|
|
437 |
buf[0] = command & 0xff;
|
|
438 |
buf[1] = (command >> 8) & 0xff;
|
|
439 |
buf[2] = (command >> 16) & 0xff;
|
|
440 |
|
|
441 |
dwt_writetodevice(GPIO_CTRL_ID, GPIO_DIR_OFFSET, GPIO_DIR_LEN, buf);
|
|
442 |
}
|
|
443 |
|
|
444 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
445 |
* @fn dwt_setgpiovalue()
|
|
446 |
*
|
|
447 |
* @brief This is used to set GPIO value as (1) or (0) only applies if the GPIO is configured as output
|
|
448 |
*
|
|
449 |
* input parameters
|
|
450 |
* @param gpioNum - this is the GPIO to configure - see DWT_GxP0... DWT_GxP8
|
|
451 |
* @param value - this sets the GPIO value - see DWT_GxP0... DWT_GxP8
|
|
452 |
*
|
|
453 |
* output parameters
|
|
454 |
*
|
|
455 |
* no return value
|
|
456 |
*/
|
|
457 |
void dwt_setgpiovalue(uint32 gpioNum, uint32 value)
|
|
458 |
{
|
|
459 |
uint8 buf[GPIO_DOUT_LEN];
|
|
460 |
uint32 command = value | gpioNum;
|
|
461 |
|
|
462 |
buf[0] = command & 0xff;
|
|
463 |
buf[1] = (command >> 8) & 0xff;
|
|
464 |
buf[2] = (command >> 16) & 0xff;
|
|
465 |
|
|
466 |
dwt_writetodevice(GPIO_CTRL_ID, GPIO_DOUT_OFFSET, GPIO_DOUT_LEN, buf);
|
|
467 |
}
|
|
468 |
|
|
469 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
470 |
* @fn dwt_getgpiovalue()
|
|
471 |
*
|
|
472 |
* @brief This is used to return 1 or 0 depending if the depending if the GPIO is high or low, only one GPIO should
|
|
473 |
* be tested at a time
|
|
474 |
*
|
|
475 |
* input parameters
|
|
476 |
* @param gpioNum - this is the GPIO to configure - see DWT_GxP0... DWT_GxP8
|
|
477 |
*
|
|
478 |
* output parameters
|
|
479 |
*
|
|
480 |
* return int (1 or 0)
|
|
481 |
*/
|
|
482 |
int dwt_getgpiovalue(uint32 gpioNum)
|
|
483 |
{
|
|
484 |
return ((dwt_read32bitoffsetreg(GPIO_CTRL_ID, GPIO_RAW_OFFSET) & gpioNum)? 1 : 0);
|
|
485 |
}
|
|
486 |
|
|
487 |
|
|
488 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
489 |
* @fn dwt_geticrefvolt()
|
|
490 |
*
|
|
491 |
* @brief This is used to return the read V measured @ 3.3 V value recorded in OTP address 0x8 (VBAT_ADDRESS)
|
|
492 |
*
|
|
493 |
* NOTE: dwt_initialise() must be called prior to this function so that it can return a relevant value.
|
|
494 |
*
|
|
495 |
* input parameters
|
|
496 |
*
|
|
497 |
* output parameters
|
|
498 |
*
|
|
499 |
* returns the 8 bit V bat value as programmed in the factory
|
|
500 |
*/
|
|
501 |
uint8 dwt_geticrefvolt(void)
|
|
502 |
{
|
|
503 |
#ifdef DWT_API_ERROR_CHECK
|
|
504 |
assert(pdw1000local->otp_mask & DWT_READ_OTP_BAT);
|
|
505 |
#endif
|
|
506 |
return pdw1000local->vBatP;
|
|
507 |
}
|
|
508 |
|
|
509 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
510 |
* @fn dwt_geticreftemp()
|
|
511 |
*
|
|
512 |
* @brief This is used to return the read T measured @ 23 C value recorded in OTP address 0x9 (VTEMP_ADDRESS)
|
|
513 |
*
|
|
514 |
* NOTE: dwt_initialise() must be called prior to this function so that it can return a relevant value.
|
|
515 |
*
|
|
516 |
* input parameters
|
|
517 |
*
|
|
518 |
* output parameters
|
|
519 |
*
|
|
520 |
* returns the 8 bit V temp value as programmed in the factory
|
|
521 |
*/
|
|
522 |
uint8 dwt_geticreftemp(void)
|
|
523 |
{
|
|
524 |
#ifdef DWT_API_ERROR_CHECK
|
|
525 |
assert(pdw1000local->otp_mask & DWT_READ_OTP_TMP);
|
|
526 |
#endif
|
|
527 |
return pdw1000local->tempP;
|
|
528 |
}
|
|
529 |
|
|
530 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
531 |
* @fn dwt_getpartid()
|
|
532 |
*
|
|
533 |
* @brief This is used to return the read part ID (or chip ID) of the device
|
|
534 |
*
|
|
535 |
* NOTE: dwt_initialise() must be called prior to this function so that it can return a relevant value (stored in OTP).
|
|
536 |
*
|
|
537 |
* input parameters
|
|
538 |
*
|
|
539 |
* output parameters
|
|
540 |
*
|
|
541 |
* returns the 32 bit part ID (or chip ID) value as programmed in the factory
|
|
542 |
*/
|
|
543 |
uint32 dwt_getpartid(void)
|
|
544 |
{
|
|
545 |
#ifdef DWT_API_ERROR_CHECK
|
|
546 |
assert(pdw1000local->otp_mask & DWT_READ_OTP_PID);
|
|
547 |
#endif
|
|
548 |
|
|
549 |
return pdw1000local->partID;
|
|
550 |
}
|
|
551 |
|
|
552 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
553 |
* @fn dwt_getlotid()
|
|
554 |
*
|
|
555 |
* @brief This is used to return the read lot ID of the device
|
|
556 |
*
|
|
557 |
* NOTE: dwt_initialise() must be called prior to this function so that it can return a relevant value.
|
|
558 |
*
|
|
559 |
* input parameters
|
|
560 |
*
|
|
561 |
* output parameters
|
|
562 |
*
|
|
563 |
* returns the 32 bit lot ID value as programmed in the factory
|
|
564 |
*/
|
|
565 |
uint32 dwt_getlotid(void)
|
|
566 |
{
|
|
567 |
#ifdef DWT_API_ERROR_CHECK
|
|
568 |
assert(pdw1000local->otp_mask & DWT_READ_OTP_LID);
|
|
569 |
#endif
|
|
570 |
|
|
571 |
return pdw1000local->lotID;
|
|
572 |
}
|
|
573 |
|
|
574 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
575 |
* @fn dwt_readdevid()
|
|
576 |
*
|
|
577 |
* @brief This is used to return the read device type and revision information of the DW1000 device (MP part is 0xDECA0130)
|
|
578 |
*
|
|
579 |
* input parameters
|
|
580 |
*
|
|
581 |
* output parameters
|
|
582 |
*
|
|
583 |
* returns the read value which for DW1000 is 0xDECA0130
|
|
584 |
*/
|
|
585 |
uint32 dwt_readdevid(void)
|
|
586 |
{
|
|
587 |
return dwt_read32bitoffsetreg(DEV_ID_ID,0);
|
|
588 |
}
|
|
589 |
|
|
590 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
591 |
* @fn dwt_configuretxrf()
|
|
592 |
*
|
|
593 |
* @brief This function provides the API for the configuration of the TX spectrum
|
|
594 |
* including the power and pulse generator delay. The input is a pointer to the data structure
|
|
595 |
* of type dwt_txconfig_t that holds all the configurable items.
|
|
596 |
*
|
|
597 |
* input parameters
|
|
598 |
* @param config - pointer to the txrf configuration structure, which contains the tx rf config data
|
|
599 |
*
|
|
600 |
* output parameters
|
|
601 |
*
|
|
602 |
* no return value
|
|
603 |
*/
|
|
604 |
void dwt_configuretxrf(dwt_txconfig_t *config)
|
|
605 |
{
|
|
606 |
|
|
607 |
// Configure RF TX PG_DELAY
|
|
608 |
dwt_write8bitoffsetreg(TX_CAL_ID, TC_PGDELAY_OFFSET, config->PGdly);
|
|
609 |
|
|
610 |
// Configure TX power
|
|
611 |
dwt_write32bitreg(TX_POWER_ID, config->power);
|
|
612 |
|
|
613 |
}
|
|
614 |
|
|
615 |
|
|
616 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
617 |
* @fn dwt_configurefor64plen()
|
|
618 |
* - Use default OPS table should be used with following register modifications:
|
|
619 |
* These modifications optimise the default OPS configuration further for 64 length preamble use case
|
|
620 |
*
|
|
621 |
* NOTE: These register settings are not preserved during SLEEP/DEEPSLEEP, thus they should be programmed again after wake up
|
|
622 |
*
|
|
623 |
* input parameters
|
|
624 |
* @param prf
|
|
625 |
*
|
|
626 |
* output parameters
|
|
627 |
*
|
|
628 |
* no return value
|
|
629 |
*/
|
|
630 |
void dwt_configurefor64plen(int prf)
|
|
631 |
{
|
|
632 |
dwt_write8bitoffsetreg(CRTR_ID, CRTR_GEAR_OFFSET, DEMOD_GEAR_64L);
|
|
633 |
|
|
634 |
if(prf == DWT_PRF_16M)
|
|
635 |
{
|
|
636 |
dwt_write8bitoffsetreg(DRX_CONF_ID, DRX_TUNE2_OFFSET+2, DRX_TUNE2_UNCONF_SFD_TH_PRF16);
|
|
637 |
}
|
|
638 |
else
|
|
639 |
{
|
|
640 |
dwt_write8bitoffsetreg(DRX_CONF_ID, DRX_TUNE2_OFFSET+2, DRX_TUNE2_UNCONF_SFD_TH_PRF64);
|
|
641 |
}
|
|
642 |
}
|
|
643 |
|
|
644 |
|
|
645 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
646 |
* @fn dwt_configure()
|
|
647 |
*
|
|
648 |
* @brief This function provides the main API for the configuration of the
|
|
649 |
* DW1000 and this low-level driver. The input is a pointer to the data structure
|
|
650 |
* of type dwt_config_t that holds all the configurable items.
|
|
651 |
* The dwt_config_t structure shows which ones are supported
|
|
652 |
*
|
|
653 |
* input parameters
|
|
654 |
* @param config - pointer to the configuration structure, which contains the device configuration data.
|
|
655 |
*
|
|
656 |
* output parameters
|
|
657 |
*
|
|
658 |
* no return value
|
|
659 |
*/
|
|
660 |
void dwt_configure(dwt_config_t *config)
|
|
661 |
{
|
|
662 |
uint8 nsSfd_result = 0;
|
|
663 |
uint8 useDWnsSFD = 0;
|
|
664 |
uint8 chan = config->chan ;
|
|
665 |
uint32 regval ;
|
|
666 |
uint16 reg16 = lde_replicaCoeff[config->rxCode];
|
|
667 |
uint8 prfIndex = config->prf - DWT_PRF_16M;
|
|
668 |
uint8 bw = ((chan == 4) || (chan == 7)) ? 1 : 0 ; // Select wide or narrow band
|
|
669 |
|
|
670 |
#ifdef DWT_API_ERROR_CHECK
|
|
671 |
assert(config->dataRate <= DWT_BR_6M8);
|
|
672 |
assert(config->rxPAC <= DWT_PAC64);
|
|
673 |
assert((chan >= 1) && (chan <= 7) && (chan != 6));
|
|
674 |
assert(((config->prf == DWT_PRF_64M) && (config->txCode >= 9) && (config->txCode <= 24))
|
|
675 |
|| ((config->prf == DWT_PRF_16M) && (config->txCode >= 1) && (config->txCode <= 8)));
|
|
676 |
assert(((config->prf == DWT_PRF_64M) && (config->rxCode >= 9) && (config->rxCode <= 24))
|
|
677 |
|| ((config->prf == DWT_PRF_16M) && (config->rxCode >= 1) && (config->rxCode <= 8)));
|
|
678 |
assert((config->txPreambLength == DWT_PLEN_64) || (config->txPreambLength == DWT_PLEN_128) || (config->txPreambLength == DWT_PLEN_256)
|
|
679 |
|| (config->txPreambLength == DWT_PLEN_512) || (config->txPreambLength == DWT_PLEN_1024) || (config->txPreambLength == DWT_PLEN_1536)
|
|
680 |
|| (config->txPreambLength == DWT_PLEN_2048) || (config->txPreambLength == DWT_PLEN_4096));
|
|
681 |
assert((config->phrMode == DWT_PHRMODE_STD) || (config->phrMode == DWT_PHRMODE_EXT));
|
|
682 |
#endif
|
|
683 |
|
|
684 |
// For 110 kbps we need a special setup
|
|
685 |
if(DWT_BR_110K == config->dataRate)
|
|
686 |
{
|
|
687 |
pdw1000local->sysCFGreg |= SYS_CFG_RXM110K ;
|
|
688 |
reg16 >>= 3; // lde_replicaCoeff must be divided by 8
|
|
689 |
}
|
|
690 |
else
|
|
691 |
{
|
|
692 |
pdw1000local->sysCFGreg &= (~SYS_CFG_RXM110K) ;
|
|
693 |
}
|
|
694 |
|
|
695 |
pdw1000local->longFrames = config->phrMode ;
|
|
696 |
|
|
697 |
pdw1000local->sysCFGreg &= ~SYS_CFG_PHR_MODE_11;
|
|
698 |
pdw1000local->sysCFGreg |= (SYS_CFG_PHR_MODE_11 & ((uint32)config->phrMode << SYS_CFG_PHR_MODE_SHFT));
|
|
699 |
|
|
700 |
dwt_write32bitreg(SYS_CFG_ID,pdw1000local->sysCFGreg) ;
|
|
701 |
// Set the lde_replicaCoeff
|
|
702 |
dwt_write16bitoffsetreg(LDE_IF_ID, LDE_REPC_OFFSET, reg16) ;
|
|
703 |
|
|
704 |
_dwt_configlde(prfIndex);
|
|
705 |
|
|
706 |
// Configure PLL2/RF PLL block CFG/TUNE (for a given channel)
|
|
707 |
dwt_write32bitoffsetreg(FS_CTRL_ID, FS_PLLCFG_OFFSET, fs_pll_cfg[chan_idx[chan]]);
|
|
708 |
dwt_write8bitoffsetreg(FS_CTRL_ID, FS_PLLTUNE_OFFSET, fs_pll_tune[chan_idx[chan]]);
|
|
709 |
|
|
710 |
// Configure RF RX blocks (for specified channel/bandwidth)
|
|
711 |
dwt_write8bitoffsetreg(RF_CONF_ID, RF_RXCTRLH_OFFSET, rx_config[bw]);
|
|
712 |
|
|
713 |
// Configure RF TX blocks (for specified channel and PRF)
|
|
714 |
// Configure RF TX control
|
|
715 |
dwt_write32bitoffsetreg(RF_CONF_ID, RF_TXCTRL_OFFSET, tx_config[chan_idx[chan]]);
|
|
716 |
|
|
717 |
// Configure the baseband parameters (for specified PRF, bit rate, PAC, and SFD settings)
|
|
718 |
// DTUNE0
|
|
719 |
dwt_write16bitoffsetreg(DRX_CONF_ID, DRX_TUNE0b_OFFSET, sftsh[config->dataRate][config->nsSFD]);
|
|
720 |
|
|
721 |
// DTUNE1
|
|
722 |
dwt_write16bitoffsetreg(DRX_CONF_ID, DRX_TUNE1a_OFFSET, dtune1[prfIndex]);
|
|
723 |
|
|
724 |
if(config->dataRate == DWT_BR_110K)
|
|
725 |
{
|
|
726 |
dwt_write16bitoffsetreg(DRX_CONF_ID, DRX_TUNE1b_OFFSET, DRX_TUNE1b_110K);
|
|
727 |
}
|
|
728 |
else
|
|
729 |
{
|
|
730 |
if(config->txPreambLength == DWT_PLEN_64)
|
|
731 |
{
|
|
732 |
dwt_write16bitoffsetreg(DRX_CONF_ID, DRX_TUNE1b_OFFSET, DRX_TUNE1b_6M8_PRE64);
|
|
733 |
dwt_write8bitoffsetreg(DRX_CONF_ID, DRX_TUNE4H_OFFSET, DRX_TUNE4H_PRE64);
|
|
734 |
}
|
|
735 |
else
|
|
736 |
{
|
|
737 |
dwt_write16bitoffsetreg(DRX_CONF_ID, DRX_TUNE1b_OFFSET, DRX_TUNE1b_850K_6M8);
|
|
738 |
dwt_write8bitoffsetreg(DRX_CONF_ID, DRX_TUNE4H_OFFSET, DRX_TUNE4H_PRE128PLUS);
|
|
739 |
}
|
|
740 |
}
|
|
741 |
|
|
742 |
// DTUNE2
|
|
743 |
dwt_write32bitoffsetreg(DRX_CONF_ID, DRX_TUNE2_OFFSET, digital_bb_config[prfIndex][config->rxPAC]);
|
|
744 |
|
|
745 |
// DTUNE3 (SFD timeout)
|
|
746 |
// Don't allow 0 - SFD timeout will always be enabled
|
|
747 |
if(config->sfdTO == 0)
|
|
748 |
{
|
|
749 |
config->sfdTO = DWT_SFDTOC_DEF;
|
|
750 |
}
|
|
751 |
dwt_write16bitoffsetreg(DRX_CONF_ID, DRX_SFDTOC_OFFSET, config->sfdTO);
|
|
752 |
|
|
753 |
// Configure AGC parameters
|
|
754 |
dwt_write32bitoffsetreg( AGC_CFG_STS_ID, 0xC, agc_config.lo32);
|
|
755 |
dwt_write16bitoffsetreg( AGC_CFG_STS_ID, 0x4, agc_config.target[prfIndex]);
|
|
756 |
|
|
757 |
// Set (non-standard) user SFD for improved performance,
|
|
758 |
if(config->nsSFD)
|
|
759 |
{
|
|
760 |
// Write non standard (DW) SFD length
|
|
761 |
dwt_write8bitoffsetreg(USR_SFD_ID, 0x00, dwnsSFDlen[config->dataRate]);
|
|
762 |
nsSfd_result = 3 ;
|
|
763 |
useDWnsSFD = 1 ;
|
|
764 |
}
|
|
765 |
regval = (CHAN_CTRL_TX_CHAN_MASK & (chan << CHAN_CTRL_TX_CHAN_SHIFT)) | // Transmit Channel
|
|
766 |
(CHAN_CTRL_RX_CHAN_MASK & (chan << CHAN_CTRL_RX_CHAN_SHIFT)) | // Receive Channel
|
|
767 |
(CHAN_CTRL_RXFPRF_MASK & ((uint32)config->prf << CHAN_CTRL_RXFPRF_SHIFT)) | // RX PRF
|
|
768 |
((CHAN_CTRL_TNSSFD|CHAN_CTRL_RNSSFD) & ((uint32)nsSfd_result << CHAN_CTRL_TNSSFD_SHIFT)) | // nsSFD enable RX&TX
|
|
769 |
(CHAN_CTRL_DWSFD & ((uint32)useDWnsSFD << CHAN_CTRL_DWSFD_SHIFT)) | // Use DW nsSFD
|
|
770 |
(CHAN_CTRL_TX_PCOD_MASK & ((uint32)config->txCode << CHAN_CTRL_TX_PCOD_SHIFT)) | // TX Preamble Code
|
|
771 |
(CHAN_CTRL_RX_PCOD_MASK & ((uint32)config->rxCode << CHAN_CTRL_RX_PCOD_SHIFT)) ; // RX Preamble Code
|
|
772 |
|
|
773 |
dwt_write32bitreg(CHAN_CTRL_ID,regval) ;
|
|
774 |
|
|
775 |
// Set up TX Preamble Size, PRF and Data Rate
|
|
776 |
pdw1000local->txFCTRL = ((uint32)(config->txPreambLength | config->prf) << TX_FCTRL_TXPRF_SHFT) | ((uint32)config->dataRate << TX_FCTRL_TXBR_SHFT);
|
|
777 |
dwt_write32bitreg(TX_FCTRL_ID, pdw1000local->txFCTRL);
|
|
778 |
|
|
779 |
// 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
|
|
780 |
// SYS_CTRL write below works around this issue, by simultaneously initiating and aborting a transmission, which correctly initialises the SFD
|
|
781 |
// after its configuration or reconfiguration.
|
|
782 |
// 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).
|
|
783 |
dwt_write8bitoffsetreg(SYS_CTRL_ID, SYS_CTRL_OFFSET, SYS_CTRL_TXSTRT | SYS_CTRL_TRXOFF); // Request TX start and TRX off at the same time
|
|
784 |
} // end dwt_configure()
|
|
785 |
|
|
786 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
787 |
* @fn dwt_setrxantennadelay()
|
|
788 |
*
|
|
789 |
* @brief This API function writes the antenna delay (in time units) to RX registers
|
|
790 |
*
|
|
791 |
* input parameters:
|
|
792 |
* @param rxDelay - this is the total (RX) antenna delay value, which
|
|
793 |
* will be programmed into the RX register
|
|
794 |
*
|
|
795 |
* output parameters
|
|
796 |
*
|
|
797 |
* no return value
|
|
798 |
*/
|
|
799 |
void dwt_setrxantennadelay(uint16 rxDelay)
|
|
800 |
{
|
|
801 |
// Set the RX antenna delay for auto TX timestamp adjustment
|
|
802 |
dwt_write16bitoffsetreg(LDE_IF_ID, LDE_RXANTD_OFFSET, rxDelay);
|
|
803 |
}
|
|
804 |
|
|
805 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
806 |
* @fn dwt_settxantennadelay()
|
|
807 |
*
|
|
808 |
* @brief This API function writes the antenna delay (in time units) to TX registers
|
|
809 |
*
|
|
810 |
* input parameters:
|
|
811 |
* @param txDelay - this is the total (TX) antenna delay value, which
|
|
812 |
* will be programmed into the TX delay register
|
|
813 |
*
|
|
814 |
* output parameters
|
|
815 |
*
|
|
816 |
* no return value
|
|
817 |
*/
|
|
818 |
void dwt_settxantennadelay(uint16 txDelay)
|
|
819 |
{
|
|
820 |
// Set the TX antenna delay for auto TX timestamp adjustment
|
|
821 |
dwt_write16bitoffsetreg(TX_ANTD_ID, TX_ANTD_OFFSET, txDelay);
|
|
822 |
}
|
|
823 |
|
|
824 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
825 |
* @fn dwt_writetxdata()
|
|
826 |
*
|
|
827 |
* @brief This API function writes the supplied TX data into the DW1000's
|
|
828 |
* TX buffer. The input parameters are the data length in bytes and a pointer
|
|
829 |
* to those data bytes.
|
|
830 |
*
|
|
831 |
* input parameters
|
|
832 |
* @param txFrameLength - This is the total frame length, including the two byte CRC.
|
|
833 |
* Note: this is the length of TX message (including the 2 byte CRC) - max is 1023
|
|
834 |
* standard PHR mode allows up to 127 bytes
|
|
835 |
* if > 127 is programmed, DWT_PHRMODE_EXT needs to be set in the phrMode configuration
|
|
836 |
* see dwt_configure function
|
|
837 |
* @param txFrameBytes - Pointer to the user?s buffer containing the data to send.
|
|
838 |
* @param txBufferOffset - This specifies an offset in the DW1000?s TX Buffer at which to start writing data.
|
|
839 |
*
|
|
840 |
* output parameters
|
|
841 |
*
|
|
842 |
* returns DWT_SUCCESS for success, or DWT_ERROR for error
|
|
843 |
*/
|
|
844 |
int dwt_writetxdata(uint16 txFrameLength, uint8 *txFrameBytes, uint16 txBufferOffset)
|
|
845 |
{
|
|
846 |
#ifdef DWT_API_ERROR_CHECK
|
|
847 |
assert(txFrameLength >= 2);
|
|
848 |
assert((pdw1000local->longFrames && (txFrameLength <= 1023)) || (txFrameLength <= 127));
|
|
849 |
assert((txBufferOffset + txFrameLength) <= 1024);
|
|
850 |
#endif
|
|
851 |
|
|
852 |
if ((txBufferOffset + txFrameLength) <= 1024)
|
|
853 |
{
|
|
854 |
// Write the data to the IC TX buffer, (-2 bytes for auto generated CRC)
|
|
855 |
dwt_writetodevice( TX_BUFFER_ID, txBufferOffset, txFrameLength-2, txFrameBytes);
|
|
856 |
return DWT_SUCCESS;
|
|
857 |
}
|
|
858 |
else
|
|
859 |
{
|
|
860 |
return DWT_ERROR;
|
|
861 |
}
|
|
862 |
} // end dwt_writetxdata()
|
|
863 |
|
|
864 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
865 |
* @fn dwt_writetxfctrl()
|
|
866 |
*
|
|
867 |
* @brief This API function configures the TX frame control register before the transmission of a frame
|
|
868 |
*
|
|
869 |
* input parameters:
|
|
870 |
* @param txFrameLength - this is the length of TX message (including the 2 byte CRC) - max is 1023
|
|
871 |
* NOTE: standard PHR mode allows up to 127 bytes
|
|
872 |
* if > 127 is programmed, DWT_PHRMODE_EXT needs to be set in the phrMode configuration
|
|
873 |
* see dwt_configure function
|
|
874 |
* @param txBufferOffset - the offset in the tx buffer to start writing the data
|
|
875 |
* @param ranging - 1 if this is a ranging frame, else 0
|
|
876 |
*
|
|
877 |
* output parameters
|
|
878 |
*
|
|
879 |
* no return value
|
|
880 |
*/
|
|
881 |
void dwt_writetxfctrl(uint16 txFrameLength, uint16 txBufferOffset, int ranging)
|
|
882 |
{
|
|
883 |
|
|
884 |
#ifdef DWT_API_ERROR_CHECK
|
|
885 |
assert((pdw1000local->longFrames && (txFrameLength <= 1023)) || (txFrameLength <= 127));
|
|
886 |
assert((txBufferOffset + txFrameLength) <= 1024);
|
|
887 |
assert((ranging == 0) || (ranging == 1))
|
|
888 |
#endif
|
|
889 |
|
|
890 |
// Write the frame length to the TX frame control register
|
|
891 |
// pdw1000local->txFCTRL has kept configured bit rate information
|
|
892 |
uint32 reg32 = pdw1000local->txFCTRL | txFrameLength | ((uint32)txBufferOffset << TX_FCTRL_TXBOFFS_SHFT) | ((uint32)ranging << TX_FCTRL_TR_SHFT);
|
|
893 |
dwt_write32bitreg(TX_FCTRL_ID, reg32);
|
|
894 |
} // end dwt_writetxfctrl()
|
|
895 |
|
|
896 |
|
|
897 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
898 |
* @fn dwt_readrxdata()
|
|
899 |
*
|
|
900 |
* @brief This is used to read the data from the RX buffer, from an offset location give by offset parameter
|
|
901 |
*
|
|
902 |
* input parameters
|
|
903 |
* @param buffer - the buffer into which the data will be read
|
|
904 |
* @param length - the length of data to read (in bytes)
|
|
905 |
* @param rxBufferOffset - the offset in the rx buffer from which to read the data
|
|
906 |
*
|
|
907 |
* output parameters
|
|
908 |
*
|
|
909 |
* no return value
|
|
910 |
*/
|
|
911 |
void dwt_readrxdata(uint8 *buffer, uint16 length, uint16 rxBufferOffset)
|
|
912 |
{
|
|
913 |
dwt_readfromdevice(RX_BUFFER_ID,rxBufferOffset,length,buffer) ;
|
|
914 |
}
|
|
915 |
|
|
916 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
917 |
* @fn dwt_readaccdata()
|
|
918 |
*
|
|
919 |
* @brief This is used to read the data from the Accumulator buffer, from an offset location give by offset parameter
|
|
920 |
*
|
|
921 |
* NOTE: Because of an internal memory access delay when reading the accumulator the first octet output is a dummy octet
|
|
922 |
* that should be discarded. This is true no matter what sub-index the read begins at.
|
|
923 |
*
|
|
924 |
* input parameters
|
|
925 |
* @param buffer - the buffer into which the data will be read
|
|
926 |
* @param length - the length of data to read (in bytes)
|
|
927 |
* @param accOffset - the offset in the acc buffer from which to read the data
|
|
928 |
*
|
|
929 |
* output parameters
|
|
930 |
*
|
|
931 |
* no return value
|
|
932 |
*/
|
|
933 |
void dwt_readaccdata(uint8 *buffer, uint16 len, uint16 accOffset)
|
|
934 |
{
|
|
935 |
// Force on the ACC clocks if we are sequenced
|
|
936 |
_dwt_enableclocks(READ_ACC_ON);
|
|
937 |
|
|
938 |
dwt_readfromdevice(ACC_MEM_ID,accOffset,len,buffer) ;
|
|
939 |
|
|
940 |
_dwt_enableclocks(READ_ACC_OFF); // Revert clocks back
|
|
941 |
}
|
|
942 |
|
|
943 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
944 |
* @fn dwt_readcarrierintegrator()
|
|
945 |
*
|
|
946 |
* @brief This is used to read the RX carrier integrator value (relating to the frequency offset of the TX node)
|
|
947 |
*
|
|
948 |
* NOTE: This is a 21-bit signed quantity, the function sign extends the most significant bit, which is bit #20
|
|
949 |
* (numbering from bit zero) to return a 32-bit signed integer value.
|
|
950 |
*
|
|
951 |
* input parameters - NONE
|
|
952 |
*
|
|
953 |
* return value - the (int32) signed carrier integrator value.
|
|
954 |
* A positive value means the local RX clock is running faster than the remote TX device.
|
|
955 |
*/
|
|
956 |
|
|
957 |
#define B20_SIGN_EXTEND_TEST (0x00100000UL)
|
|
958 |
#define B20_SIGN_EXTEND_MASK (0xFFF00000UL)
|
|
959 |
|
|
960 |
int32 dwt_readcarrierintegrator(void)
|
|
961 |
{
|
|
962 |
uint32 regval = 0 ;
|
|
963 |
int j ;
|
|
964 |
uint8 buffer[DRX_CARRIER_INT_LEN] ;
|
|
965 |
|
|
966 |
/* Read 3 bytes into buffer (21-bit quantity) */
|
|
967 |
|
|
968 |
dwt_readfromdevice(DRX_CONF_ID,DRX_CARRIER_INT_OFFSET,DRX_CARRIER_INT_LEN, buffer) ;
|
|
969 |
|
|
970 |
for (j = 2 ; j >= 0 ; j --) // arrange the three bytes into an unsigned integer value
|
|
971 |
{
|
|
972 |
regval = (regval << 8) + buffer[j] ;
|
|
973 |
}
|
|
974 |
|
|
975 |
if (regval & B20_SIGN_EXTEND_TEST) regval |= B20_SIGN_EXTEND_MASK ; // sign extend bit #20 to whole word
|
|
976 |
else regval &= DRX_CARRIER_INT_MASK ; // make sure upper bits are clear if not sign extending
|
|
977 |
|
|
978 |
return (int32) regval ; // cast unsigned value to signed quantity.
|
|
979 |
}
|
|
980 |
|
|
981 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
982 |
* @fn dwt_readdiagnostics()
|
|
983 |
*
|
|
984 |
* @brief this function reads the RX signal quality diagnostic data
|
|
985 |
*
|
|
986 |
* input parameters
|
|
987 |
* @param diagnostics - diagnostic structure pointer, this will contain the diagnostic data read from the DW1000
|
|
988 |
*
|
|
989 |
* output parameters
|
|
990 |
*
|
|
991 |
* no return value
|
|
992 |
*/
|
|
993 |
void dwt_readdiagnostics(dwt_rxdiag_t *diagnostics)
|
|
994 |
{
|
|
995 |
// Read the HW FP index
|
|
996 |
diagnostics->firstPath = dwt_read16bitoffsetreg(RX_TIME_ID, RX_TIME_FP_INDEX_OFFSET);
|
|
997 |
|
|
998 |
// LDE diagnostic data
|
|
999 |
diagnostics->maxNoise = dwt_read16bitoffsetreg(LDE_IF_ID, LDE_THRESH_OFFSET);
|
|
1000 |
|
|
1001 |
// Read all 8 bytes in one SPI transaction
|
|
1002 |
dwt_readfromdevice(RX_FQUAL_ID, 0x0, 8, (uint8*)&diagnostics->stdNoise);
|
|
1003 |
|
|
1004 |
diagnostics->firstPathAmp1 = dwt_read16bitoffsetreg(RX_TIME_ID, RX_TIME_FP_AMPL1_OFFSET);
|
|
1005 |
|
|
1006 |
diagnostics->rxPreamCount = (dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXPACC_MASK) >> RX_FINFO_RXPACC_SHIFT ;
|
|
1007 |
}
|
|
1008 |
|
|
1009 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
1010 |
* @fn dwt_readtxtimestamp()
|
|
1011 |
*
|
|
1012 |
* @brief This is used to read the TX timestamp (adjusted with the programmed antenna delay)
|
|
1013 |
*
|
|
1014 |
* input parameters
|
|
1015 |
* @param timestamp - a pointer to a 5-byte buffer which will store the read TX timestamp time
|
|
1016 |
*
|
|
1017 |
* output parameters - the timestamp buffer will contain the value after the function call
|
|
1018 |
*
|
|
1019 |
* no return value
|
|
1020 |
*/
|
|
1021 |
void dwt_readtxtimestamp(uint8 * timestamp)
|
|
1022 |
{
|
|
1023 |
dwt_readfromdevice(TX_TIME_ID, TX_TIME_TX_STAMP_OFFSET, TX_TIME_TX_STAMP_LEN, timestamp) ; // Read bytes directly into buffer
|
|
1024 |
}
|
|
1025 |
|
|
1026 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
1027 |
* @fn dwt_readtxtimestamphi32()
|
|
1028 |
*
|
|
1029 |
* @brief This is used to read the high 32-bits of the TX timestamp (adjusted with the programmed antenna delay)
|
|
1030 |
*
|
|
1031 |
* input parameters
|
|
1032 |
*
|
|
1033 |
* output parameters
|
|
1034 |
*
|
|
1035 |
* returns high 32-bits of TX timestamp
|
|
1036 |
*/
|
|
1037 |
uint32 dwt_readtxtimestamphi32(void)
|
|
1038 |
{
|
|
1039 |
return dwt_read32bitoffsetreg(TX_TIME_ID, 1); // Offset is 1 to get the 4 upper bytes out of 5
|
|
1040 |
}
|
|
1041 |
|
|
1042 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
1043 |
* @fn dwt_readtxtimestamplo32()
|
|
1044 |
*
|
|
1045 |
* @brief This is used to read the low 32-bits of the TX timestamp (adjusted with the programmed antenna delay)
|
|
1046 |
*
|
|
1047 |
* input parameters
|
|
1048 |
*
|
|
1049 |
* output parameters
|
|
1050 |
*
|
|
1051 |
* returns low 32-bits of TX timestamp
|
|
1052 |
*/
|
|
1053 |
uint32 dwt_readtxtimestamplo32(void)
|
|
1054 |
{
|
|
1055 |
return dwt_read32bitreg(TX_TIME_ID); // Read TX TIME as a 32-bit register to get the 4 lower bytes out of 5
|
|
1056 |
}
|
|
1057 |
|
|
1058 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
1059 |
* @fn dwt_readrxtimestamp()
|
|
1060 |
*
|
|
1061 |
* @brief This is used to read the RX timestamp (adjusted time of arrival)
|
|
1062 |
*
|
|
1063 |
* input parameters
|
|
1064 |
* @param timestamp - a pointer to a 5-byte buffer which will store the read RX timestamp time
|
|
1065 |
*
|
|
1066 |
* output parameters - the timestamp buffer will contain the value after the function call
|
|
1067 |
*
|
|
1068 |
* no return value
|
|
1069 |
*/
|
|
1070 |
void dwt_readrxtimestamp(uint8 * timestamp)
|
|
1071 |
{
|
|
1072 |
dwt_readfromdevice(RX_TIME_ID, RX_TIME_RX_STAMP_OFFSET, RX_TIME_RX_STAMP_LEN, timestamp) ; // Get the adjusted time of arrival
|
|
1073 |
}
|
|
1074 |
|
|
1075 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
1076 |
* @fn dwt_readrxtimestamphi32()
|
|
1077 |
*
|
|
1078 |
* @brief This is used to read the high 32-bits of the RX timestamp (adjusted with the programmed antenna delay)
|
|
1079 |
*
|
|
1080 |
* input parameters
|
|
1081 |
*
|
|
1082 |
* output parameters
|
|
1083 |
*
|
|
1084 |
* returns high 32-bits of RX timestamp
|
|
1085 |
*/
|
|
1086 |
uint32 dwt_readrxtimestamphi32(void)
|
|
1087 |
{
|
|
1088 |
return dwt_read32bitoffsetreg(RX_TIME_ID, 1); // Offset is 1 to get the 4 upper bytes out of 5
|
|
1089 |
}
|
|
1090 |
|
|
1091 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
1092 |
* @fn dwt_readrxtimestamplo32()
|
|
1093 |
*
|
|
1094 |
* @brief This is used to read the low 32-bits of the RX timestamp (adjusted with the programmed antenna delay)
|
|
1095 |
*
|
|
1096 |
* input parameters
|
|
1097 |
*
|
|
1098 |
* output parameters
|
|
1099 |
*
|
|
1100 |
* returns low 32-bits of RX timestamp
|
|
1101 |
*/
|
|
1102 |
uint32 dwt_readrxtimestamplo32(void)
|
|
1103 |
{
|
|
1104 |
return dwt_read32bitreg(RX_TIME_ID); // Read RX TIME as a 32-bit register to get the 4 lower bytes out of 5
|
|
1105 |
}
|
|
1106 |
|
|
1107 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
1108 |
* @fn dwt_readsystimestamphi32()
|
|
1109 |
*
|
|
1110 |
* @brief This is used to read the high 32-bits of the system time
|
|
1111 |
*
|
|
1112 |
* input parameters
|
|
1113 |
*
|
|
1114 |
* output parameters
|
|
1115 |
*
|
|
1116 |
* returns high 32-bits of system time timestamp
|
|
1117 |
*/
|
|
1118 |
uint32 dwt_readsystimestamphi32(void)
|
|
1119 |
{
|
|
1120 |
return dwt_read32bitoffsetreg(SYS_TIME_ID, 1); // Offset is 1 to get the 4 upper bytes out of 5
|
|
1121 |
}
|
|
1122 |
|
|
1123 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
1124 |
* @fn dwt_readsystime()
|
|
1125 |
*
|
|
1126 |
* @brief This is used to read the system time
|
|
1127 |
*
|
|
1128 |
* input parameters
|
|
1129 |
* @param timestamp - a pointer to a 5-byte buffer which will store the read system time
|
|
1130 |
*
|
|
1131 |
* output parameters
|
|
1132 |
* @param timestamp - the timestamp buffer will contain the value after the function call
|
|
1133 |
*
|
|
1134 |
* no return value
|
|
1135 |
*/
|
|
1136 |
void dwt_readsystime(uint8 * timestamp)
|
|
1137 |
{
|
|
1138 |
dwt_readfromdevice(SYS_TIME_ID, SYS_TIME_OFFSET, SYS_TIME_LEN, timestamp) ;
|
|
1139 |
}
|
|
1140 |
|
|
1141 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
1142 |
* @fn dwt_writetodevice()
|
|
1143 |
*
|
|
1144 |
* @brief this function is used to write to the DW1000 device registers
|
|
1145 |
* Notes:
|
|
1146 |
* 1. Firstly we create a header (the first byte is a header byte)
|
|
1147 |
* 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
|
|
1148 |
* b. set bit-7 (or with 0x80) for write operation
|
|
1149 |
* 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
|
|
1150 |
*
|
|
1151 |
* 2. Write the header followed by the data bytes to the DW1000 device
|
|
1152 |
*
|
|
1153 |
*
|
|
1154 |
* input parameters:
|
|
1155 |
* @param recordNumber - ID of register file or buffer being accessed
|
|
1156 |
* @param index - byte index into register file or buffer being accessed
|
|
1157 |
* @param length - number of bytes being written
|
|
1158 |
* @param buffer - pointer to buffer containing the 'length' bytes to be written
|
|
1159 |
*
|
|
1160 |
* output parameters
|
|
1161 |
*
|
|
1162 |
* no return value
|
|
1163 |
*/
|
|
1164 |
void dwt_writetodevice
|
|
1165 |
(
|
|
1166 |
uint16 recordNumber,
|
|
1167 |
uint16 index,
|
|
1168 |
uint32 length,
|
|
1169 |
const uint8 *buffer
|
|
1170 |
)
|
|
1171 |
{
|
|
1172 |
uint8 header[3] ; // Buffer to compose header in
|
|
1173 |
int cnt = 0; // Counter for length of header
|
|
1174 |
#ifdef DWT_API_ERROR_CHECK
|
|
1175 |
assert(recordNumber <= 0x3F); // Record number is limited to 6-bits.
|
|
1176 |
#endif
|
|
1177 |
|
|
1178 |
// Write message header selecting WRITE operation and addresses as appropriate (this is one to three bytes long)
|
|
1179 |
if (index == 0) // For index of 0, no sub-index is required
|
|
1180 |
{
|
|
1181 |
header[cnt++] = 0x80 | recordNumber ; // Bit-7 is WRITE operation, bit-6 zero=NO sub-addressing, bits 5-0 is reg file id
|
|
1182 |
}
|
|
1183 |
else
|
|
1184 |
{
|
|
1185 |
#ifdef DWT_API_ERROR_CHECK
|
|
1186 |
assert((index <= 0x7FFF) && ((index + length) <= 0x7FFF)); // Index and sub-addressable area are limited to 15-bits.
|
|
1187 |
#endif
|
|
1188 |
header[cnt++] = 0xC0 | recordNumber ; // Bit-7 is WRITE operation, bit-6 one=sub-address follows, bits 5-0 is reg file id
|
|
1189 |
|
|
1190 |
if (index <= 127) // For non-zero index < 127, just a single sub-index byte is required
|
|
1191 |
{
|
|
1192 |
header[cnt++] = (uint8)index ; // Bit-7 zero means no extension, bits 6-0 is index.
|
|
1193 |
}
|
|
1194 |
else
|
|
1195 |
{
|
|
1196 |
header[cnt++] = 0x80 | (uint8)(index) ; // Bit-7 one means extended index, bits 6-0 is low seven bits of index.
|
|
1197 |
header[cnt++] = (uint8) (index >> 7) ; // 8-bit value = high eight bits of index.
|
|
1198 |
}
|
|
1199 |
}
|
|
1200 |
|
|
1201 |
// Write it to the SPI
|
|
1202 |
writetospi(cnt,header,length,buffer);
|
|
1203 |
} // end dwt_writetodevice()
|
|
1204 |
|
|
1205 |
/*! ------------------------------------------------------------------------------------------------------------------
|
|
1206 |
* @fn dwt_readfromdevice()
|
|
1207 |
*
|
|
1208 |
* @brief this function is used to read from the DW1000 device registers
|
|
1209 |
* Notes:
|
|
1210 |
* 1. Firstly we create a header (the first byte is a header byte)
|
|
1211 |
* 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
|
|
1212 |
* b. set bit-7 (or with 0x80) for write operation
|
|
1213 |
* 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
|
|
1214 |
*
|
|
1215 |
* 2. Write the header followed by the data bytes to the DW1000 device
|
|
1216 |
* 3. Store the read data in the input buffer
|
|
1217 |
*
|
|
1218 |
* input parameters:
|
|
1219 |
* @param recordNumber - ID of register file or buffer being accessed
|
|
1220 |
* @param index - byte index into register file or buffer being accessed
|
|
1221 |
* @param length - number of bytes being read
|
|
1222 |
* @param buffer - pointer to buffer in which to return the read data.
|
|
1223 |
*
|
|
1224 |
* output parameters
|
|
1225 |
*
|
|
1226 |
* no return value
|
|
1227 |
*/
|
|
1228 |
void dwt_readfromdevice
|
|
1229 |
(
|
|
1230 |
uint16 recordNumber,
|
|
1231 |
uint16 index,
|
|
1232 |
uint32 length,
|
|
1233 |
uint8 *buffer
|
|
1234 |
)
|
|
1235 |
{
|
|
1236 |
uint8 header[3] ; // Buffer to compose header in
|
|
1237 |
int cnt = 0; // Counter for length of header
|
|
1238 |
#ifdef DWT_API_ERROR_CHECK
|
|
1239 |
assert(recordNumber <= 0x3F); // Record number is limited to 6-bits.
|
|
1240 |
#endif
|
|
1241 |
|
|
1242 |
// Write message header selecting READ operation and addresses as appropriate (this is one to three bytes long)
|
|
1243 |
if (index == 0) // For index of 0, no sub-index is required
|
|
1244 |
{
|
|
1245 |
header[cnt++] = (uint8) recordNumber ; // Bit-7 zero is READ operation, bit-6 zero=NO sub-addressing, bits 5-0 is reg file id
|
|
1246 |
}
|
|
1247 |
else
|
|
1248 |
{
|
|
1249 |
#ifdef DWT_API_ERROR_CHECK
|
|
1250 |
assert((index <= 0x7FFF) && ((index + length) <= 0x7FFF)); // Index and sub-addressable area are limited to 15-bits.
|
|
1251 |
#endif
|
|
1252 |
header[cnt++] = (uint8)(0x40 | recordNumber) ; // Bit-7 zero is READ operation, bit-6 one=sub-address follows, bits 5-0 is reg file id
|
|
1253 |
|
|
1254 |
if (index <= 127) // For non-zero index < 127, just a single sub-index byte is required
|
|
1255 |
{
|