amiro-lld / drivers / DW1000 / v2 / decadriver / deca_device.c @ 99ca7610
History | View | Annotate | Download (142.18 KB)
| 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
|