DW1000 UWB driver based on work of Matthias Grob & Manuel Stalder - ETH Zürich - 2015

Dependencies:   BurstSPI

Committer:
AndyA
Date:
Tue Apr 05 13:43:54 2016 +0000
Revision:
16:2080adef6fa6
Parent:
1:dcbd071f38d5
Added comments;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AndyA 0:bddb8cd5e7df 1 #include "DW1000.h"
AndyA 0:bddb8cd5e7df 2
AndyA 0:bddb8cd5e7df 3 #define SPIRATE_PLL (5*1000*1000)
AndyA 0:bddb8cd5e7df 4 #define SPIRATE_OSC (2*1000*1000)
AndyA 0:bddb8cd5e7df 5
AndyA 0:bddb8cd5e7df 6 DW1000::DW1000(UWBMode setup, PinName MOSI, PinName MISO, PinName SCLK, PinName CS, PinName IRQ) : irq(IRQ), spi(MOSI, MISO, SCLK), cs(CS)
AndyA 0:bddb8cd5e7df 7 {
AndyA 0:bddb8cd5e7df 8 setCallbacks(NULL, NULL);
AndyA 0:bddb8cd5e7df 9
AndyA 0:bddb8cd5e7df 10 deselect(); // Chip must be deselected first
AndyA 0:bddb8cd5e7df 11 spi.format(8,0); // Setup the spi for standard 8 bit data and SPI-Mode 0 (GPIO5, GPIO6 open circuit or ground on DW1000)
AndyA 0:bddb8cd5e7df 12 spi.frequency(SPIRATE_PLL); // with a 1MHz clock rate (worked up to 49MHz in our Test)
AndyA 0:bddb8cd5e7df 13
AndyA 0:bddb8cd5e7df 14 resetAll(); // we do a soft reset of the DW1000 everytime the driver starts
AndyA 0:bddb8cd5e7df 15
AndyA 0:bddb8cd5e7df 16 switch (setup) {
AndyA 0:bddb8cd5e7df 17 case user110k: // values from Matthias Grob & Manuel Stalder - ETH Zürich - library
AndyA 0:bddb8cd5e7df 18 //Those values are for the 110kbps mode (5, 16MHz, 1024 Symbols) and are quite complete
AndyA 0:bddb8cd5e7df 19 writeRegister16(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE1, 0x8870); //AGC_TUNE1 for 16MHz PRF
AndyA 0:bddb8cd5e7df 20 writeRegister32(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE2, 0x2502A907); //AGC_TUNE2 (Universal)
AndyA 0:bddb8cd5e7df 21 writeRegister16(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE3, 0x0055); //AGC_TUNE3 (Universal)
AndyA 0:bddb8cd5e7df 22
AndyA 0:bddb8cd5e7df 23 writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE0B, 0x000A); //DRX_TUNE0b for 110kbps
AndyA 0:bddb8cd5e7df 24 writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE1A, 0x0087); //DRX_TUNE1a for 16MHz PRF
AndyA 0:bddb8cd5e7df 25 writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE1B, 0x0064); //DRX_TUNE1b for 110kbps & > 1024 symbols
AndyA 0:bddb8cd5e7df 26 writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x351A009A); //PAC size for 1024 symbols preamble & 16MHz PRF
AndyA 0:bddb8cd5e7df 27 //writeRegister32(DW1000_DRX_CONF, 0x08, 0x371A011D); //PAC size for 2048 symbols preamble
AndyA 0:bddb8cd5e7df 28
AndyA 0:bddb8cd5e7df 29 writeRegister8 (DW1000_LDE_CTRL, DWLDE_LDE_CFG1, 0xD); //LDE_CFG1
AndyA 0:bddb8cd5e7df 30 writeRegister16(DW1000_LDE_CTRL, DWLDE_LDE_CFG2, 0x1607); //LDE_CFG2 for 16MHz PRF
AndyA 0:bddb8cd5e7df 31
AndyA 0:bddb8cd5e7df 32 writeRegister32(DW1000_TX_POWER, 0, 0x28282828); //Power for channel 5
AndyA 0:bddb8cd5e7df 33
AndyA 0:bddb8cd5e7df 34 writeRegister8(DW1000_RF_CONF, DWRFCONF_RF_RXCTRLH, 0xD8); //RF_RXCTRLH for channel 5
AndyA 0:bddb8cd5e7df 35 writeRegister32(DW1000_RF_CONF, DWRFCONF_RF_TXCTRL, 0x001E3FE0); //RF_TXCTRL for channel 5
AndyA 0:bddb8cd5e7df 36
AndyA 0:bddb8cd5e7df 37 writeRegister8 (DW1000_TX_CAL, DWTXCAL_TC_PGDELAY, 0xC0); //TC_PGDELAY for channel 5
AndyA 0:bddb8cd5e7df 38
AndyA 0:bddb8cd5e7df 39 writeRegister32 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLCFG, 0x0800041D); //FS_PLLCFG for channel 5
AndyA 0:bddb8cd5e7df 40 writeRegister8 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLTUNE, 0xBE); // changed from 0xA6 //FS_PLLTUNE for channel 5
AndyA 0:bddb8cd5e7df 41
AndyA 0:bddb8cd5e7df 42 loadLDE(); // important everytime DW1000 initialises/awakes otherwise the LDE algorithm must be turned off or there's receiving malfunction see User Manual LDELOAD on p22 & p158
AndyA 0:bddb8cd5e7df 43
AndyA 0:bddb8cd5e7df 44 // 110kbps CAUTION: a lot of other registers have to be set for an optimized operation on 110kbps
AndyA 0:bddb8cd5e7df 45 writeRegister16(DW1000_TX_FCTRL, 1, 0x0800 | 0x0100 | 0x0080); // use 1024 symbols preamble (0x0800) (previously 2048 - 0x2800), 16MHz pulse repetition frequency (0x0100), 110kbps bit rate (0x0080) see p.69 of DW1000 User Manual
AndyA 0:bddb8cd5e7df 46 writeRegister8(DW1000_SYS_CFG, 2, 0x44); // enable special receiving option for 110kbps (disable smartTxPower)!! (0x44) see p.64 of DW1000 User Manual [DO NOT enable 1024 byte frames (0x03) becuase it generates disturbance of ranging don't know why...]
AndyA 0:bddb8cd5e7df 47
AndyA 0:bddb8cd5e7df 48 writeRegister16(DW1000_TX_ANTD, 0, 16384); // set TX and RX Antenna delay to neutral because we calibrate afterwards
AndyA 0:bddb8cd5e7df 49 writeRegister16(DW1000_LDE_CTRL, DWLDE_LDE_RXANTD, 16384); // = 2^14 a quarter of the range of the 16-Bit register which corresponds to zero calibration in a round trip (TX1+RX2+TX2+RX1)
AndyA 0:bddb8cd5e7df 50 break;
AndyA 0:bddb8cd5e7df 51
AndyA 0:bddb8cd5e7df 52 case tunedDefault: // User Manual "2.5.5 Default Configurations that should be modified" p. 22
AndyA 0:bddb8cd5e7df 53 //Those values are for the standard mode (6.8Mbps, 5, 16Mhz, 32 Symbols) and are (may be?) INCOMPLETE!
AndyA 0:bddb8cd5e7df 54 writeRegister16(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE1, 0x8870);
AndyA 0:bddb8cd5e7df 55 writeRegister32(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE2, 0x2502A907);
AndyA 0:bddb8cd5e7df 56 writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x311A002D);
AndyA 0:bddb8cd5e7df 57 writeRegister8(DW1000_DRX_CONF, DWDRX_DRX_TUNE0B, 0x0001);
AndyA 0:bddb8cd5e7df 58 writeRegister8(DW1000_DRX_CONF, DWDRX_DRX_TUNE1A, 0x0087);
AndyA 0:bddb8cd5e7df 59 writeRegister8(DW1000_DRX_CONF, DWDRX_DRX_TUNE1B, 0x0020);
AndyA 0:bddb8cd5e7df 60 writeRegister8 (DW1000_LDE_CTRL, DWLDE_LDE_CFG1, 0xD);
AndyA 0:bddb8cd5e7df 61 writeRegister16(DW1000_LDE_CTRL, DWLDE_LDE_CFG2, 0x1607);
AndyA 0:bddb8cd5e7df 62 writeRegister32(DW1000_TX_POWER, 0, 0x0E082848);
AndyA 0:bddb8cd5e7df 63 // writeRegister32(DW1000_TX_POWER, 0, 0x75757575);
AndyA 0:bddb8cd5e7df 64 writeRegister32(DW1000_RF_CONF, DWRFCONF_RF_TXCTRL, 0x001E3FE0);
AndyA 0:bddb8cd5e7df 65 writeRegister8 (DW1000_TX_CAL, DWTXCAL_TC_PGDELAY, 0xC0);
AndyA 0:bddb8cd5e7df 66 writeRegister8 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLTUNE, 0xBE);
AndyA 0:bddb8cd5e7df 67
AndyA 0:bddb8cd5e7df 68 loadLDE(); // important everytime DW1000 initialises/awakes otherwise the LDE algorithm must be turned off or there's receiving malfunction see User Manual LDELOAD on p22 & p158
AndyA 0:bddb8cd5e7df 69
AndyA 0:bddb8cd5e7df 70 writeRegister32(DW1000_GPIO_CTRL,DWGPIO_GPIO_MODE,0x00001400);
AndyA 0:bddb8cd5e7df 71 writeRegister16(DW1000_PMSC,DWPMSC_PMSC_LEDC,0x0120);
AndyA 0:bddb8cd5e7df 72
AndyA 0:bddb8cd5e7df 73 // writeRegister8(DW1000_SYS_CFG, 3, 0x20); // enable auto RX reenable
AndyA 0:bddb8cd5e7df 74
AndyA 0:bddb8cd5e7df 75 setRxDelay(0);
AndyA 0:bddb8cd5e7df 76 setTxDelay(0);
AndyA 0:bddb8cd5e7df 77
AndyA 0:bddb8cd5e7df 78 break;
AndyA 0:bddb8cd5e7df 79 case defaultConfig:
AndyA 0:bddb8cd5e7df 80 default:
AndyA 0:bddb8cd5e7df 81 loadLDE(); // important everytime DW1000 initialises/awakes otherwise the LDE algorithm must be turned off or there's receiving malfunction see User Manual LDELOAD on p22 & p158
AndyA 0:bddb8cd5e7df 82 break;
AndyA 0:bddb8cd5e7df 83 }
AndyA 0:bddb8cd5e7df 84
AndyA 0:bddb8cd5e7df 85 writeRegister8(DW1000_SYS_CFG, 3, 0x20); // enable auto reenabling receiver after error
AndyA 0:bddb8cd5e7df 86
AndyA 0:bddb8cd5e7df 87 irq.rise(this, &DW1000::ISR); // attach interrupt handler to rising edge of interrupt pin from DW1000
AndyA 0:bddb8cd5e7df 88 }
AndyA 0:bddb8cd5e7df 89
AndyA 0:bddb8cd5e7df 90 void DW1000::setRxDelay(uint16_t ticks)
AndyA 0:bddb8cd5e7df 91 {
AndyA 0:bddb8cd5e7df 92 writeRegister16(DW1000_LDE_CTRL, DWLDE_LDE_RXANTD, ticks);
AndyA 0:bddb8cd5e7df 93 }
AndyA 0:bddb8cd5e7df 94 void DW1000::setTxDelay(uint16_t ticks)
AndyA 0:bddb8cd5e7df 95 {
AndyA 0:bddb8cd5e7df 96 writeRegister16(DW1000_TX_ANTD, 0, ticks);
AndyA 0:bddb8cd5e7df 97 }
AndyA 0:bddb8cd5e7df 98
AndyA 0:bddb8cd5e7df 99 void DW1000::setCallbacks(void (*callbackRX)(void), void (*callbackTX)(void))
AndyA 0:bddb8cd5e7df 100 {
AndyA 0:bddb8cd5e7df 101 bool RX = false;
AndyA 0:bddb8cd5e7df 102 bool TX = false;
AndyA 0:bddb8cd5e7df 103 if (callbackRX) {
AndyA 0:bddb8cd5e7df 104 DW1000::callbackRX.attach(callbackRX);
AndyA 0:bddb8cd5e7df 105 RX = true;
AndyA 0:bddb8cd5e7df 106 }
AndyA 0:bddb8cd5e7df 107 if (callbackTX) {
AndyA 0:bddb8cd5e7df 108 DW1000::callbackTX.attach(callbackTX);
AndyA 0:bddb8cd5e7df 109 TX = true;
AndyA 0:bddb8cd5e7df 110 }
AndyA 0:bddb8cd5e7df 111 setInterrupt(RX,TX);
AndyA 0:bddb8cd5e7df 112 }
AndyA 0:bddb8cd5e7df 113
AndyA 0:bddb8cd5e7df 114 uint32_t DW1000::getDeviceID()
AndyA 0:bddb8cd5e7df 115 {
AndyA 0:bddb8cd5e7df 116 uint32_t result;
AndyA 0:bddb8cd5e7df 117 readRegister(DW1000_DEV_ID, 0, (uint8_t*)&result, 4);
AndyA 0:bddb8cd5e7df 118 return result;
AndyA 0:bddb8cd5e7df 119 }
AndyA 0:bddb8cd5e7df 120
AndyA 0:bddb8cd5e7df 121 uint64_t DW1000::getEUI()
AndyA 0:bddb8cd5e7df 122 {
AndyA 0:bddb8cd5e7df 123 uint64_t result;
AndyA 0:bddb8cd5e7df 124 readRegister(DW1000_EUI, 0, (uint8_t*)&result, 8);
AndyA 0:bddb8cd5e7df 125 return result;
AndyA 0:bddb8cd5e7df 126 }
AndyA 0:bddb8cd5e7df 127
AndyA 0:bddb8cd5e7df 128 void DW1000::setEUI(uint64_t EUI)
AndyA 0:bddb8cd5e7df 129 {
AndyA 0:bddb8cd5e7df 130 writeRegister(DW1000_EUI, 0, (uint8_t*)&EUI, 8);
AndyA 0:bddb8cd5e7df 131 }
AndyA 0:bddb8cd5e7df 132
AndyA 0:bddb8cd5e7df 133
AndyA 0:bddb8cd5e7df 134 float DW1000::getVoltage()
AndyA 0:bddb8cd5e7df 135 {
AndyA 0:bddb8cd5e7df 136 uint8_t data;
AndyA 0:bddb8cd5e7df 137
AndyA 0:bddb8cd5e7df 138 writeRegister8(DW1000_RF_CONF, 0x11, 0x80);
AndyA 0:bddb8cd5e7df 139 writeRegister8(DW1000_RF_CONF, 0x12, 0x0A);
AndyA 0:bddb8cd5e7df 140 writeRegister8(DW1000_RF_CONF, 0x12, 0x0F);
AndyA 0:bddb8cd5e7df 141 writeRegister8(DW1000_TX_CAL, 0x00, 0x01);
AndyA 0:bddb8cd5e7df 142 writeRegister8(DW1000_TX_CAL, 0x00, 0x00);
AndyA 0:bddb8cd5e7df 143 data = readRegister8(DW1000_TX_CAL, 0x03); // get the 8-Bit reading for Voltage
AndyA 1:dcbd071f38d5 144 float Voltage = (float)(data - (readOTP(0x08)&0x00ff)) *0.00578 + 3.3;
AndyA 0:bddb8cd5e7df 145 return Voltage;
AndyA 0:bddb8cd5e7df 146 }
AndyA 0:bddb8cd5e7df 147
AndyA 0:bddb8cd5e7df 148 float DW1000::getTemperature()
AndyA 0:bddb8cd5e7df 149 {
AndyA 0:bddb8cd5e7df 150 uint8_t data;
AndyA 0:bddb8cd5e7df 151
AndyA 0:bddb8cd5e7df 152 writeRegister8(DW1000_RF_CONF, 0x11, 0x80);
AndyA 0:bddb8cd5e7df 153 writeRegister8(DW1000_RF_CONF, 0x12, 0x0A);
AndyA 0:bddb8cd5e7df 154 writeRegister8(DW1000_RF_CONF, 0x12, 0x0F);
AndyA 0:bddb8cd5e7df 155 writeRegister8(DW1000_TX_CAL, 0x00, 0x01);
AndyA 0:bddb8cd5e7df 156 writeRegister8(DW1000_TX_CAL, 0x00, 0x00);
AndyA 0:bddb8cd5e7df 157 data = readRegister16(DW1000_TX_CAL, 0x04); // get the 8-Bit reading for Temperature
AndyA 1:dcbd071f38d5 158 float temperature = (float)(data - (readOTP(0x09) & 0x00ff))*0.9 + 23;
AndyA 0:bddb8cd5e7df 159 return temperature;
AndyA 0:bddb8cd5e7df 160 }
AndyA 0:bddb8cd5e7df 161
AndyA 0:bddb8cd5e7df 162
AndyA 0:bddb8cd5e7df 163 uint64_t DW1000::getStatus()
AndyA 0:bddb8cd5e7df 164 {
AndyA 0:bddb8cd5e7df 165 return readRegister40(DW1000_SYS_STATUS, 0);
AndyA 0:bddb8cd5e7df 166 }
AndyA 0:bddb8cd5e7df 167
AndyA 0:bddb8cd5e7df 168 uint64_t DW1000::getRXTimestamp()
AndyA 0:bddb8cd5e7df 169 {
AndyA 0:bddb8cd5e7df 170 return readRegister40(DW1000_RX_TIME, 0);
AndyA 0:bddb8cd5e7df 171 }
AndyA 0:bddb8cd5e7df 172
AndyA 0:bddb8cd5e7df 173 uint64_t DW1000::getTXTimestamp()
AndyA 0:bddb8cd5e7df 174 {
AndyA 0:bddb8cd5e7df 175 return readRegister40(DW1000_TX_TIME, 0);
AndyA 0:bddb8cd5e7df 176 }
AndyA 0:bddb8cd5e7df 177
AndyA 0:bddb8cd5e7df 178 void DW1000::sendFrame(uint8_t* message, uint16_t length)
AndyA 0:bddb8cd5e7df 179 {
AndyA 0:bddb8cd5e7df 180 //if (length >= 1021) length = 1021; // check for maximim length a frame can have with 1024 Byte frames [not used, see constructor]
AndyA 0:bddb8cd5e7df 181 if (length >= 125) length = 125; // check for maximim length a frame can have with 127 Byte frames
AndyA 0:bddb8cd5e7df 182 uint8_t len_7bit = length;
AndyA 0:bddb8cd5e7df 183 writeRegister(DW1000_TX_BUFFER, 0, message, len_7bit); // fill buffer
AndyA 0:bddb8cd5e7df 184
AndyA 0:bddb8cd5e7df 185 /* support for frames over 127 bytes
AndyA 0:bddb8cd5e7df 186 uint8_t backup = readRegister8(DW1000_TX_FCTRL, 1); // put length of frame
AndyA 0:bddb8cd5e7df 187 length += 2; // including 2 CRC Bytes
AndyA 0:bddb8cd5e7df 188 length = ((backup & 0xFC) << 8) | (length & 0x03FF);
AndyA 0:bddb8cd5e7df 189 writeRegister16(DW1000_TX_FCTRL, 0, length);
AndyA 0:bddb8cd5e7df 190 */
AndyA 0:bddb8cd5e7df 191 len_7bit += 2; // including 2 CRC Bytes
AndyA 0:bddb8cd5e7df 192 writeRegister8(DW1000_TX_FCTRL, 0, len_7bit);
AndyA 0:bddb8cd5e7df 193
AndyA 0:bddb8cd5e7df 194 stopTRX(); // stop receiving
AndyA 0:bddb8cd5e7df 195 writeRegister8(DW1000_SYS_CTRL, 0, 0x02 | 0x80); // trigger sending process by setting the TXSTRT bit
AndyA 0:bddb8cd5e7df 196 // startRX(); // enable receiver again
AndyA 0:bddb8cd5e7df 197 }
AndyA 0:bddb8cd5e7df 198
AndyA 0:bddb8cd5e7df 199 void DW1000::setupSyncedFrame(uint8_t* message, uint16_t length) {
AndyA 0:bddb8cd5e7df 200 //if (length >= 1021) length = 1021; // check for maximim length a frame can have with 1024 Byte frames [not used, see constructor]
AndyA 0:bddb8cd5e7df 201 if (length >= 125) length = 125; // check for maximim length a frame can have with 127 Byte frames
AndyA 0:bddb8cd5e7df 202 writeRegister(DW1000_TX_BUFFER, 0, message, length); // fill buffer
AndyA 0:bddb8cd5e7df 203
AndyA 0:bddb8cd5e7df 204 uint8_t backup = readRegister8(DW1000_TX_FCTRL, 1); // put length of frame
AndyA 0:bddb8cd5e7df 205 length += 2; // including 2 CRC Bytes
AndyA 0:bddb8cd5e7df 206 length = ((backup & 0xFC) << 8) | (length & 0x03FF);
AndyA 0:bddb8cd5e7df 207 writeRegister16(DW1000_TX_FCTRL, 0, length);
AndyA 0:bddb8cd5e7df 208 }
AndyA 0:bddb8cd5e7df 209
AndyA 0:bddb8cd5e7df 210 void DW1000::armSyncedFrame() {
AndyA 0:bddb8cd5e7df 211 stopTRX(); // stop receiving
AndyA 0:bddb8cd5e7df 212 writeRegister16(DW1000_EXT_SYNC, DWEXTSYNC_EC_CTRL, 33<<3 | 0x01); // Sync register = TX start with a wait of 33 (recomended, value must fulfill wait % 4 = 1)
AndyA 0:bddb8cd5e7df 213 }
AndyA 0:bddb8cd5e7df 214
AndyA 0:bddb8cd5e7df 215 void DW1000::sendDelayedFrame(uint8_t* message, uint16_t length, uint64_t TxTimestamp)
AndyA 0:bddb8cd5e7df 216 {
AndyA 0:bddb8cd5e7df 217 //if (length >= 1021) length = 1021; // check for maximim length a frame can have with 1024 Byte frames [not used, see constructor]
AndyA 0:bddb8cd5e7df 218 if (length >= 125) length = 125; // check for maximim length a frame can have with 127 Byte frames
AndyA 0:bddb8cd5e7df 219 writeRegister(DW1000_TX_BUFFER, 0, message, length); // fill buffer
AndyA 0:bddb8cd5e7df 220
AndyA 0:bddb8cd5e7df 221 uint8_t backup = readRegister8(DW1000_TX_FCTRL, 1); // put length of frame
AndyA 0:bddb8cd5e7df 222 length += 2; // including 2 CRC Bytes
AndyA 0:bddb8cd5e7df 223 length = ((backup & 0xFC) << 8) | (length & 0x03FF);
AndyA 0:bddb8cd5e7df 224 writeRegister16(DW1000_TX_FCTRL, 0, length);
AndyA 0:bddb8cd5e7df 225
AndyA 0:bddb8cd5e7df 226 writeRegister40(DW1000_DX_TIME, 0, TxTimestamp); //write the timestamp on which to send the message
AndyA 0:bddb8cd5e7df 227
AndyA 0:bddb8cd5e7df 228 stopTRX(); // stop receiving
AndyA 0:bddb8cd5e7df 229 writeRegister8(DW1000_SYS_CTRL, 0, 0x02 | 0x04 | 0x80); // trigger sending process by setting the TXSTRT and TXDLYS bit. Set Wait4resp to automatically enter RX mode after tx.
AndyA 0:bddb8cd5e7df 230 }
AndyA 0:bddb8cd5e7df 231
AndyA 0:bddb8cd5e7df 232 void DW1000::startRX()
AndyA 0:bddb8cd5e7df 233 {
AndyA 0:bddb8cd5e7df 234 writeRegister8(DW1000_SYS_CTRL, 0x01, 0x01); // start listening for preamble by setting the RXENAB bit
AndyA 0:bddb8cd5e7df 235 }
AndyA 0:bddb8cd5e7df 236
AndyA 0:bddb8cd5e7df 237 void DW1000::stopTRX()
AndyA 0:bddb8cd5e7df 238 {
AndyA 0:bddb8cd5e7df 239 writeRegister8(DW1000_SYS_CTRL, 0, 0x40); // disable tranceiver go back to idle mode
AndyA 0:bddb8cd5e7df 240 }
AndyA 0:bddb8cd5e7df 241
AndyA 0:bddb8cd5e7df 242 // PRIVATE Methods ------------------------------------------------------------------------------------
AndyA 0:bddb8cd5e7df 243 void DW1000::loadLDE() // initialise LDE algorithm LDELOAD User Manual p22
AndyA 0:bddb8cd5e7df 244 {
AndyA 0:bddb8cd5e7df 245 spi.frequency(SPIRATE_OSC); // with a 1MHz clock rate (worked up to 49MHz in our Test)
AndyA 0:bddb8cd5e7df 246
AndyA 0:bddb8cd5e7df 247 writeRegister16(DW1000_PMSC, 0, 0x0301); // set clock to XTAL so OTP is reliable
AndyA 0:bddb8cd5e7df 248 writeRegister16(DW1000_OTP_IF, DWOTP_OTP_CTRL, 0x8000); // set LDELOAD bit in OTP
AndyA 0:bddb8cd5e7df 249 wait_us(150);
AndyA 0:bddb8cd5e7df 250 writeRegister16(DW1000_PMSC, 0, 0x0200); // recover to PLL clock
AndyA 0:bddb8cd5e7df 251
AndyA 0:bddb8cd5e7df 252 wait_ms(1);
AndyA 0:bddb8cd5e7df 253
AndyA 0:bddb8cd5e7df 254 spi.frequency(SPIRATE_PLL); // with a 1MHz clock rate (worked up to 49MHz in our Test)
AndyA 0:bddb8cd5e7df 255
AndyA 0:bddb8cd5e7df 256 }
AndyA 0:bddb8cd5e7df 257
AndyA 0:bddb8cd5e7df 258 void DW1000::loadLDOTUNE()
AndyA 0:bddb8cd5e7df 259 {
AndyA 1:dcbd071f38d5 260 uint64_t LDOTuningValue = readOTP(0x0004);
AndyA 1:dcbd071f38d5 261 if (LDOTuningValue != 0) {
AndyA 1:dcbd071f38d5 262 LDOTuningValue = LDOTuningValue | ((uint64_t)(readOTP(0x0005) & 0x00ff) << 32);
AndyA 0:bddb8cd5e7df 263 writeRegister40(DW1000_RF_CONF,DWRFCONF_RF_LDOTUNE,LDOTuningValue);
AndyA 1:dcbd071f38d5 264 }
AndyA 0:bddb8cd5e7df 265 }
AndyA 0:bddb8cd5e7df 266
AndyA 0:bddb8cd5e7df 267 void DW1000::resetRX()
AndyA 0:bddb8cd5e7df 268 {
AndyA 0:bddb8cd5e7df 269 writeRegister8(DW1000_PMSC, 3, 0xE0); // set RX reset
AndyA 0:bddb8cd5e7df 270 writeRegister8(DW1000_PMSC, 3, 0xF0); // clear RX reset
AndyA 0:bddb8cd5e7df 271 }
AndyA 0:bddb8cd5e7df 272
AndyA 0:bddb8cd5e7df 273 void DW1000::resetAll()
AndyA 0:bddb8cd5e7df 274 {
AndyA 0:bddb8cd5e7df 275 spi.frequency(SPIRATE_OSC); // with a 1MHz clock rate (worked up to 49MHz in our Test)
AndyA 0:bddb8cd5e7df 276
AndyA 0:bddb8cd5e7df 277 writeRegister8(DW1000_PMSC, 0, 0x01); // set clock to XTAL
AndyA 0:bddb8cd5e7df 278 writeRegister8(DW1000_PMSC, 3, 0x00); // set All reset
AndyA 0:bddb8cd5e7df 279 wait_us(10); // wait for PLL to lock
AndyA 0:bddb8cd5e7df 280 writeRegister8(DW1000_PMSC, 3, 0xF0); // clear All reset
AndyA 0:bddb8cd5e7df 281
AndyA 0:bddb8cd5e7df 282 wait_ms(1);
AndyA 0:bddb8cd5e7df 283
AndyA 0:bddb8cd5e7df 284 spi.frequency(SPIRATE_PLL); // with a 1MHz clock rate (worked up to 49MHz in our Test)
AndyA 0:bddb8cd5e7df 285 }
AndyA 0:bddb8cd5e7df 286
AndyA 0:bddb8cd5e7df 287 /// After writes have been completed reset the device.
AndyA 1:dcbd071f38d5 288 bool DW1000::writeOTP(uint16_t word_address,uint32_t data)
AndyA 0:bddb8cd5e7df 289 {
AndyA 0:bddb8cd5e7df 290 spi.frequency(SPIRATE_OSC); // with a 1MHz clock rate (worked up to 49MHz in our Test)
AndyA 0:bddb8cd5e7df 291
AndyA 0:bddb8cd5e7df 292 writeRegister8(DW1000_PMSC, 0, 0x01); // set clock to XTAL
AndyA 0:bddb8cd5e7df 293 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x03); //
AndyA 0:bddb8cd5e7df 294 writeRegister16(DW1000_OTP_IF,DWOTP_OTP_WDAT,0x9220); //
AndyA 0:bddb8cd5e7df 295 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x08); //
AndyA 0:bddb8cd5e7df 296 wait_ms(1);
AndyA 0:bddb8cd5e7df 297 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x02); //
AndyA 0:bddb8cd5e7df 298 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x88); //
AndyA 0:bddb8cd5e7df 299 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x80); //
AndyA 0:bddb8cd5e7df 300 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00); //
AndyA 0:bddb8cd5e7df 301
AndyA 0:bddb8cd5e7df 302 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x05); //
AndyA 0:bddb8cd5e7df 303 writeRegister16(DW1000_OTP_IF,DWOTP_OTP_WDAT,0x000E); //
AndyA 0:bddb8cd5e7df 304 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x08); //
AndyA 0:bddb8cd5e7df 305 wait_ms(1);
AndyA 0:bddb8cd5e7df 306 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x04); //
AndyA 0:bddb8cd5e7df 307 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x88); //
AndyA 0:bddb8cd5e7df 308 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x80); //
AndyA 0:bddb8cd5e7df 309 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00); //
AndyA 0:bddb8cd5e7df 310
AndyA 0:bddb8cd5e7df 311 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x01); //
AndyA 0:bddb8cd5e7df 312 writeRegister16(DW1000_OTP_IF,DWOTP_OTP_WDAT,0x1024); //
AndyA 0:bddb8cd5e7df 313 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x08); //
AndyA 0:bddb8cd5e7df 314 wait_ms(1);
AndyA 0:bddb8cd5e7df 315 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x00); //
AndyA 0:bddb8cd5e7df 316
AndyA 0:bddb8cd5e7df 317 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00); //
AndyA 0:bddb8cd5e7df 318 writeRegister32(DW1000_OTP_IF,DWOTP_OTP_WDAT,data); //
AndyA 1:dcbd071f38d5 319 writeRegister16(DW1000_OTP_IF,DWOTP_OTP_ADDR,word_address); //
AndyA 0:bddb8cd5e7df 320 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x40); //
AndyA 0:bddb8cd5e7df 321 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00); //
AndyA 0:bddb8cd5e7df 322 wait_ms(1);
AndyA 0:bddb8cd5e7df 323
AndyA 0:bddb8cd5e7df 324 for (int i=0; i<10; i++) {
AndyA 1:dcbd071f38d5 325 if (readOTP(word_address) == data)
AndyA 0:bddb8cd5e7df 326 return true;
AndyA 0:bddb8cd5e7df 327 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x40); // retry
AndyA 0:bddb8cd5e7df 328 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00);
AndyA 0:bddb8cd5e7df 329 wait_ms(1);
AndyA 0:bddb8cd5e7df 330 }
AndyA 0:bddb8cd5e7df 331 return false;
AndyA 0:bddb8cd5e7df 332 }
AndyA 0:bddb8cd5e7df 333
AndyA 0:bddb8cd5e7df 334
AndyA 1:dcbd071f38d5 335 uint32_t DW1000::readOTP(uint16_t word_address)
AndyA 0:bddb8cd5e7df 336 {
AndyA 1:dcbd071f38d5 337 writeRegister16(DW1000_OTP_IF,DWOTP_OTP_ADDR,word_address); // write address
AndyA 0:bddb8cd5e7df 338 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x03); // read address load
AndyA 0:bddb8cd5e7df 339 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x01); // read
AndyA 0:bddb8cd5e7df 340 uint32_t data = readRegister32(DW1000_OTP_IF,DWOTP_OTP_RDAT);
AndyA 0:bddb8cd5e7df 341 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00); // OTP idle
AndyA 0:bddb8cd5e7df 342 return data;
AndyA 0:bddb8cd5e7df 343 }
AndyA 0:bddb8cd5e7df 344
AndyA 0:bddb8cd5e7df 345 void DW1000::setInterrupt(bool RX, bool TX)
AndyA 0:bddb8cd5e7df 346 {
AndyA 0:bddb8cd5e7df 347 writeRegister16(DW1000_SYS_MASK, 0, RX*0x4000 | TX*0x0080); // RX good frame 0x4000, TX done 0x0080
AndyA 0:bddb8cd5e7df 348 }
AndyA 0:bddb8cd5e7df 349
AndyA 0:bddb8cd5e7df 350 void DW1000::ISR()
AndyA 0:bddb8cd5e7df 351 {
AndyA 0:bddb8cd5e7df 352 uint64_t status = getStatus();
AndyA 0:bddb8cd5e7df 353 if (status & 0x4000) { // a frame was received
AndyA 0:bddb8cd5e7df 354 callbackRX.call();
AndyA 0:bddb8cd5e7df 355 writeRegister16(DW1000_SYS_STATUS, 0, 0x6F00); // clearing of receiving status bits
AndyA 0:bddb8cd5e7df 356 }
AndyA 0:bddb8cd5e7df 357 if (status & 0x80) { // sending complete
AndyA 0:bddb8cd5e7df 358 callbackTX.call();
AndyA 0:bddb8cd5e7df 359 writeRegister8(DW1000_SYS_STATUS, 0, 0xF8); // clearing of sending status bits
AndyA 0:bddb8cd5e7df 360 }
AndyA 0:bddb8cd5e7df 361 }
AndyA 0:bddb8cd5e7df 362
AndyA 0:bddb8cd5e7df 363 uint16_t DW1000::getFramelength()
AndyA 0:bddb8cd5e7df 364 {
AndyA 0:bddb8cd5e7df 365 uint16_t framelength = readRegister16(DW1000_RX_FINFO, 0); // get framelength
AndyA 0:bddb8cd5e7df 366 framelength = (framelength & 0x03FF) - 2; // take only the right bits and subtract the 2 CRC Bytes
AndyA 0:bddb8cd5e7df 367 return framelength;
AndyA 0:bddb8cd5e7df 368 }
AndyA 0:bddb8cd5e7df 369
AndyA 0:bddb8cd5e7df 370 // SPI Interface ------------------------------------------------------------------------------------
AndyA 0:bddb8cd5e7df 371 uint8_t DW1000::readRegister8(uint8_t reg, uint16_t subaddress)
AndyA 0:bddb8cd5e7df 372 {
AndyA 0:bddb8cd5e7df 373 uint8_t result;
AndyA 0:bddb8cd5e7df 374 readRegister(reg, subaddress, &result, 1);
AndyA 0:bddb8cd5e7df 375 return result;
AndyA 0:bddb8cd5e7df 376 }
AndyA 0:bddb8cd5e7df 377
AndyA 0:bddb8cd5e7df 378 uint16_t DW1000::readRegister16(uint8_t reg, uint16_t subaddress)
AndyA 0:bddb8cd5e7df 379 {
AndyA 0:bddb8cd5e7df 380 uint16_t result;
AndyA 0:bddb8cd5e7df 381 readRegister(reg, subaddress, (uint8_t*)&result, 2);
AndyA 0:bddb8cd5e7df 382 return result;
AndyA 0:bddb8cd5e7df 383 }
AndyA 0:bddb8cd5e7df 384
AndyA 0:bddb8cd5e7df 385 uint32_t DW1000::readRegister32(uint8_t reg, uint16_t subaddress)
AndyA 0:bddb8cd5e7df 386 {
AndyA 0:bddb8cd5e7df 387 uint32_t result;
AndyA 0:bddb8cd5e7df 388 readRegister(reg, subaddress, (uint8_t*)&result, 4);
AndyA 0:bddb8cd5e7df 389 return result;
AndyA 0:bddb8cd5e7df 390 }
AndyA 0:bddb8cd5e7df 391
AndyA 0:bddb8cd5e7df 392
AndyA 0:bddb8cd5e7df 393 uint64_t DW1000::readRegister40(uint8_t reg, uint16_t subaddress)
AndyA 0:bddb8cd5e7df 394 {
AndyA 0:bddb8cd5e7df 395 uint64_t result = 0;
AndyA 0:bddb8cd5e7df 396 readRegister(reg, subaddress, (uint8_t*)&result, 5);
AndyA 0:bddb8cd5e7df 397 return result;
AndyA 0:bddb8cd5e7df 398 }
AndyA 0:bddb8cd5e7df 399 uint64_t DW1000::readRegister64(uint8_t reg, uint16_t subaddress)
AndyA 0:bddb8cd5e7df 400 {
AndyA 0:bddb8cd5e7df 401 uint64_t result;
AndyA 0:bddb8cd5e7df 402 readRegister(reg, subaddress, (uint8_t*)&result, 8);
AndyA 0:bddb8cd5e7df 403 return result;
AndyA 0:bddb8cd5e7df 404 }
AndyA 0:bddb8cd5e7df 405
AndyA 0:bddb8cd5e7df 406 void DW1000::writeRegister8(uint8_t reg, uint16_t subaddress, uint8_t buffer)
AndyA 0:bddb8cd5e7df 407 {
AndyA 0:bddb8cd5e7df 408 writeRegister(reg, subaddress, &buffer, 1);
AndyA 0:bddb8cd5e7df 409 }
AndyA 0:bddb8cd5e7df 410
AndyA 0:bddb8cd5e7df 411 void DW1000::writeRegister16(uint8_t reg, uint16_t subaddress, uint16_t buffer)
AndyA 0:bddb8cd5e7df 412 {
AndyA 0:bddb8cd5e7df 413 writeRegister(reg, subaddress, (uint8_t*)&buffer, 2);
AndyA 0:bddb8cd5e7df 414 }
AndyA 0:bddb8cd5e7df 415
AndyA 0:bddb8cd5e7df 416 void DW1000::writeRegister32(uint8_t reg, uint16_t subaddress, uint32_t buffer)
AndyA 0:bddb8cd5e7df 417 {
AndyA 0:bddb8cd5e7df 418 writeRegister(reg, subaddress, (uint8_t*)&buffer, 4);
AndyA 0:bddb8cd5e7df 419 }
AndyA 0:bddb8cd5e7df 420
AndyA 0:bddb8cd5e7df 421 void DW1000::writeRegister40(uint8_t reg, uint16_t subaddress, uint64_t buffer)
AndyA 0:bddb8cd5e7df 422 {
AndyA 0:bddb8cd5e7df 423 writeRegister(reg, subaddress, (uint8_t*)&buffer, 5);
AndyA 0:bddb8cd5e7df 424 }
AndyA 0:bddb8cd5e7df 425
AndyA 0:bddb8cd5e7df 426 void DW1000::readRegister(uint8_t reg, uint16_t subaddress, uint8_t *buffer, int length)
AndyA 0:bddb8cd5e7df 427 {
AndyA 0:bddb8cd5e7df 428 setupTransaction(reg, subaddress, false);
AndyA 0:bddb8cd5e7df 429 for(int i=0; i<length; i++) // get data
AndyA 0:bddb8cd5e7df 430 buffer[i] = spi.write(0x00);
AndyA 0:bddb8cd5e7df 431 deselect();
AndyA 0:bddb8cd5e7df 432 }
AndyA 0:bddb8cd5e7df 433
AndyA 0:bddb8cd5e7df 434 void DW1000::writeRegister(uint8_t reg, uint16_t subaddress, uint8_t *buffer, int length)
AndyA 0:bddb8cd5e7df 435 {
AndyA 0:bddb8cd5e7df 436 setupTransaction(reg, subaddress, true);
AndyA 0:bddb8cd5e7df 437 for(int i=0; i<length; i++) // put data
AndyA 0:bddb8cd5e7df 438 spi.write(buffer[i]);
AndyA 0:bddb8cd5e7df 439 deselect();
AndyA 0:bddb8cd5e7df 440 }
AndyA 0:bddb8cd5e7df 441
AndyA 0:bddb8cd5e7df 442 void DW1000::setupTransaction(uint8_t reg, uint16_t subaddress, bool write)
AndyA 0:bddb8cd5e7df 443 {
AndyA 0:bddb8cd5e7df 444 reg |= (write * DW1000_WRITE_FLAG); // set read/write flag
AndyA 0:bddb8cd5e7df 445 select();
AndyA 0:bddb8cd5e7df 446 if (subaddress > 0) { // there's a subadress, we need to set flag and send second header byte
AndyA 0:bddb8cd5e7df 447 spi.write(reg | DW1000_SUBADDRESS_FLAG);
AndyA 0:bddb8cd5e7df 448 if (subaddress > 0x7F) { // sub address too long, we need to set flag and send third header byte
AndyA 0:bddb8cd5e7df 449 spi.write((uint8_t)(subaddress & 0x7F) | DW1000_2_SUBADDRESS_FLAG); // and
AndyA 0:bddb8cd5e7df 450 spi.write((uint8_t)(subaddress >> 7));
AndyA 0:bddb8cd5e7df 451 } else {
AndyA 0:bddb8cd5e7df 452 spi.write((uint8_t)subaddress);
AndyA 0:bddb8cd5e7df 453 }
AndyA 0:bddb8cd5e7df 454 } else {
AndyA 0:bddb8cd5e7df 455 spi.write(reg); // say which register address we want to access
AndyA 0:bddb8cd5e7df 456 }
AndyA 0:bddb8cd5e7df 457 }
AndyA 0:bddb8cd5e7df 458
AndyA 0:bddb8cd5e7df 459 void DW1000::select() // always called to start an SPI transmission
AndyA 0:bddb8cd5e7df 460 {
AndyA 0:bddb8cd5e7df 461 irq.disable_irq(); // disable interrupts from DW1000 during SPI becaus this leads to crashes! TODO: if you have other interrupt handlers attached on the micro controller, they could also interfere.
AndyA 0:bddb8cd5e7df 462 cs = 0; // set Cable Select pin low to start transmission
AndyA 0:bddb8cd5e7df 463 }
AndyA 0:bddb8cd5e7df 464
AndyA 0:bddb8cd5e7df 465 void DW1000::deselect() // always called to end an SPI transmission
AndyA 0:bddb8cd5e7df 466 {
AndyA 0:bddb8cd5e7df 467 cs = 1; // set Cable Select pin high to stop transmission
AndyA 0:bddb8cd5e7df 468 irq.enable_irq(); // reenable the interrupt handler
AndyA 0:bddb8cd5e7df 469 }