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

Dependencies:   BurstSPI

Committer:
AndyA
Date:
Mon Apr 18 16:58:27 2016 +0000
Revision:
8:0b408e77b701
Parent:
7:b13881dbb09d
Child:
9:326bf149c8bc
f

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AndyA 0:bddb8cd5e7df 1 #include "DW1000.h"
AndyA 0:bddb8cd5e7df 2
AndyA 7:b13881dbb09d 3 #define SPIRATE_PLL (10*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 8:0b408e77b701 9 DW1000Setup newSetup(DW1000Setup::fastLocationC5);
AndyA 8:0b408e77b701 10 systemConfig.applyConfig(&newSetup);
AndyA 0:bddb8cd5e7df 11
AndyA 0:bddb8cd5e7df 12 deselect(); // Chip must be deselected first
AndyA 0:bddb8cd5e7df 13 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 14 spi.frequency(SPIRATE_PLL); // with a 1MHz clock rate (worked up to 49MHz in our Test)
AndyA 0:bddb8cd5e7df 15
AndyA 0:bddb8cd5e7df 16 resetAll(); // we do a soft reset of the DW1000 everytime the driver starts
AndyA 8:0b408e77b701 17 setupRadio();
AndyA 8:0b408e77b701 18 setTxPower(250,250,250+30,250+60); // power = 23dB gain
AndyA 0:bddb8cd5e7df 19
AndyA 0:bddb8cd5e7df 20 setRxDelay(0);
AndyA 0:bddb8cd5e7df 21 setTxDelay(0);
AndyA 0:bddb8cd5e7df 22
AndyA 0:bddb8cd5e7df 23 irq.rise(this, &DW1000::ISR); // attach interrupt handler to rising edge of interrupt pin from DW1000
AndyA 0:bddb8cd5e7df 24 }
AndyA 0:bddb8cd5e7df 25
AndyA 4:5f1025df5530 26
AndyA 8:0b408e77b701 27 DW1000Setup* DW1000::getSetup() {
AndyA 8:0b408e77b701 28 return &systemConfig;
AndyA 4:5f1025df5530 29 }
AndyA 4:5f1025df5530 30
AndyA 3:1459d2aa6b97 31 void DW1000::setupRadio()
AndyA 3:1459d2aa6b97 32 {
AndyA 3:1459d2aa6b97 33 setupAGC();
AndyA 3:1459d2aa6b97 34 setupRxConfig();
AndyA 3:1459d2aa6b97 35 setupLDE();
AndyA 3:1459d2aa6b97 36 setupChannel();
AndyA 3:1459d2aa6b97 37 setupAnalogRF();
AndyA 3:1459d2aa6b97 38 setupFreqSynth();
AndyA 3:1459d2aa6b97 39 setupTxCalibration();
AndyA 3:1459d2aa6b97 40 setupTxFrameCtrl();
AndyA 3:1459d2aa6b97 41 setupSystemConfig();
AndyA 3:1459d2aa6b97 42
AndyA 3:1459d2aa6b97 43 }
AndyA 3:1459d2aa6b97 44
AndyA 3:1459d2aa6b97 45 void DW1000::setupAGC()
AndyA 3:1459d2aa6b97 46 {
AndyA 3:1459d2aa6b97 47
AndyA 3:1459d2aa6b97 48 writeRegister16(DW1000_AGC_CTRL, DWAGCCTRL_AGC_CTRL1, 0x0001);
AndyA 4:5f1025df5530 49 if (systemConfig.getPRF() == DW1000Setup::prf16MHz)
AndyA 3:1459d2aa6b97 50 writeRegister16(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE1, 0x8870);
AndyA 3:1459d2aa6b97 51 else
AndyA 3:1459d2aa6b97 52 writeRegister16(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE1, 0x889B);
AndyA 3:1459d2aa6b97 53
AndyA 3:1459d2aa6b97 54 writeRegister32(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE2, 0x2502A907);
AndyA 3:1459d2aa6b97 55 writeRegister16(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE3, 0x0035);
AndyA 3:1459d2aa6b97 56 }
AndyA 3:1459d2aa6b97 57
AndyA 3:1459d2aa6b97 58 void DW1000::setupSystemConfig()
AndyA 3:1459d2aa6b97 59 {
AndyA 3:1459d2aa6b97 60 uint32_t valueToUse = 0;
AndyA 3:1459d2aa6b97 61 valueToUse |= 1<<9; // IRQ output is active high (default)
AndyA 3:1459d2aa6b97 62 valueToUse |= 1<<12; // Disable double buffered Rx (default)
AndyA 3:1459d2aa6b97 63
AndyA 3:1459d2aa6b97 64 // valueToUse |= 3<<16; // enable long (>125bytes data) packets
AndyA 3:1459d2aa6b97 65
AndyA 4:5f1025df5530 66 if (!systemConfig.getSmartPower())
AndyA 3:1459d2aa6b97 67 valueToUse |= 1<<18; // disable smart power
AndyA 3:1459d2aa6b97 68
AndyA 4:5f1025df5530 69 if (systemConfig.getDataRate() == DW1000Setup::kbps110)
AndyA 3:1459d2aa6b97 70 valueToUse |= 1<<22;
AndyA 3:1459d2aa6b97 71
AndyA 4:5f1025df5530 72 valueToUse |= 1<<29;// enable auto reenabling receiver after error
AndyA 4:5f1025df5530 73
AndyA 4:5f1025df5530 74 writeRegister32(DW1000_SYS_CFG, 0, valueToUse);
AndyA 3:1459d2aa6b97 75 }
AndyA 3:1459d2aa6b97 76
AndyA 3:1459d2aa6b97 77 void DW1000::setupRxConfig()
AndyA 3:1459d2aa6b97 78 {
AndyA 3:1459d2aa6b97 79
AndyA 4:5f1025df5530 80 switch (systemConfig.getDataRate()) {
AndyA 4:5f1025df5530 81 case DW1000Setup::kbps110:
AndyA 4:5f1025df5530 82 if (systemConfig.getSfd() == DW1000Setup::standard)
AndyA 3:1459d2aa6b97 83 writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE0B, 0x000A);
AndyA 3:1459d2aa6b97 84 else
AndyA 3:1459d2aa6b97 85 writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE0B, 0x0016);
AndyA 3:1459d2aa6b97 86 break;
AndyA 4:5f1025df5530 87 case DW1000Setup::kbps850:
AndyA 4:5f1025df5530 88 if (systemConfig.getSfd() == DW1000Setup::standard)
AndyA 3:1459d2aa6b97 89 writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE0B, 0x0001);
AndyA 3:1459d2aa6b97 90 else
AndyA 3:1459d2aa6b97 91 writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE0B, 0x0006);
AndyA 3:1459d2aa6b97 92 break;
AndyA 4:5f1025df5530 93 case DW1000Setup::kbps6800:
AndyA 3:1459d2aa6b97 94 default:
AndyA 4:5f1025df5530 95 if (systemConfig.getSfd() == DW1000Setup::standard)
AndyA 3:1459d2aa6b97 96 writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE0B, 0x0001);
AndyA 3:1459d2aa6b97 97 else
AndyA 3:1459d2aa6b97 98 writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE0B, 0x0002);
AndyA 3:1459d2aa6b97 99 break;
AndyA 3:1459d2aa6b97 100 }
AndyA 3:1459d2aa6b97 101
AndyA 4:5f1025df5530 102 if (systemConfig.getPRF() == DW1000Setup::prf16MHz)
AndyA 3:1459d2aa6b97 103 writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE1A, 0x0087); //DRX_TUNE1a for 16MHz PRF
AndyA 3:1459d2aa6b97 104 else
AndyA 3:1459d2aa6b97 105 writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE1A, 0x008D);
AndyA 3:1459d2aa6b97 106
AndyA 4:5f1025df5530 107 switch (systemConfig.getPreambleLength()) {
AndyA 4:5f1025df5530 108 case DW1000Setup::pre1536:
AndyA 4:5f1025df5530 109 case DW1000Setup::pre2048:
AndyA 4:5f1025df5530 110 case DW1000Setup::pre4096:
AndyA 3:1459d2aa6b97 111 writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE1B, 0x0064); //DRX_TUNE1b for 110kbps & > 1024 symbols
AndyA 3:1459d2aa6b97 112 break;
AndyA 3:1459d2aa6b97 113 default: // 128 to 1024
AndyA 3:1459d2aa6b97 114 writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE1B, 0x0020); //DRX_TUNE1b for 128- 1024 symbols
AndyA 3:1459d2aa6b97 115 break;
AndyA 4:5f1025df5530 116 case DW1000Setup::pre64:
AndyA 3:1459d2aa6b97 117 writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE1B, 0x0010); //DRX_TUNE1b for 64 symbols
AndyA 3:1459d2aa6b97 118 break;
AndyA 3:1459d2aa6b97 119 }
AndyA 3:1459d2aa6b97 120
AndyA 4:5f1025df5530 121 switch (systemConfig.getPreambleLength()) {
AndyA 4:5f1025df5530 122 case DW1000Setup::pre64:
AndyA 4:5f1025df5530 123 case DW1000Setup::pre128: // PAC = 8
AndyA 4:5f1025df5530 124 if (systemConfig.getPRF() == DW1000Setup::prf16MHz)
AndyA 3:1459d2aa6b97 125 writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x311A002D); //DRX_TUNE2 PAC 8 for 64MHz PRF
AndyA 3:1459d2aa6b97 126 else
AndyA 3:1459d2aa6b97 127 writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x313B006B); //DRX_TUNE2 PAC 8 for 64MHz PRF
AndyA 3:1459d2aa6b97 128 break;
AndyA 4:5f1025df5530 129 case DW1000Setup::pre256:
AndyA 4:5f1025df5530 130 case DW1000Setup::pre512: // PAC = 16
AndyA 4:5f1025df5530 131 if (systemConfig.getPRF() == DW1000Setup::prf16MHz)
AndyA 3:1459d2aa6b97 132 writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x331A0052); //DRX_TUNE2 PAC 16 for 64MHz PRF
AndyA 3:1459d2aa6b97 133 else
AndyA 3:1459d2aa6b97 134 writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x333B00BE); //DRX_TUNE2 PAC 16 for 64MHz PRF
AndyA 3:1459d2aa6b97 135 break;
AndyA 4:5f1025df5530 136 case DW1000Setup::pre1024: // PAC = 32
AndyA 4:5f1025df5530 137 if (systemConfig.getPRF() == DW1000Setup::prf16MHz)
AndyA 3:1459d2aa6b97 138 writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x351A009A); //DRX_TUNE2 PAC 32 for 64MHz PRF
AndyA 3:1459d2aa6b97 139 else
AndyA 3:1459d2aa6b97 140 writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x353B015E); //DRX_TUNE2 PAC 32 for 64MHz PRF
AndyA 3:1459d2aa6b97 141 break;
AndyA 4:5f1025df5530 142 case DW1000Setup::pre1536:
AndyA 4:5f1025df5530 143 case DW1000Setup::pre2048:
AndyA 4:5f1025df5530 144 case DW1000Setup::pre4096: // PAC = 64
AndyA 4:5f1025df5530 145 if (systemConfig.getPRF() == DW1000Setup::prf16MHz)
AndyA 3:1459d2aa6b97 146 writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x371A011D); //DRX_TUNE2 PAC 64 for 64MHz PRF
AndyA 3:1459d2aa6b97 147 else
AndyA 3:1459d2aa6b97 148 writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x373B0296); //DRX_TUNE2 PAC 64 for 64MHz PRF
AndyA 0:bddb8cd5e7df 149 break;
AndyA 0:bddb8cd5e7df 150 }
AndyA 0:bddb8cd5e7df 151
AndyA 3:1459d2aa6b97 152
AndyA 4:5f1025df5530 153 if (systemConfig.getPreambleLength() == DW1000Setup::pre64)
AndyA 3:1459d2aa6b97 154 writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE4H, 0x0010);
AndyA 3:1459d2aa6b97 155 else
AndyA 3:1459d2aa6b97 156 writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE4H, 0x0028);
AndyA 3:1459d2aa6b97 157
AndyA 3:1459d2aa6b97 158 }
AndyA 3:1459d2aa6b97 159
AndyA 3:1459d2aa6b97 160
AndyA 3:1459d2aa6b97 161 void DW1000::setupLDE()
AndyA 3:1459d2aa6b97 162 {
AndyA 3:1459d2aa6b97 163
AndyA 3:1459d2aa6b97 164 writeRegister8 (DW1000_LDE_CTRL, DWLDE_LDE_CFG1, 0x13 | 0x03<<5); //NTM = 13 (12 may be better in some situations. PMULT = 3
AndyA 3:1459d2aa6b97 165
AndyA 4:5f1025df5530 166 if (systemConfig.getPRF() == DW1000Setup::prf16MHz)
AndyA 3:1459d2aa6b97 167 writeRegister16(DW1000_LDE_CTRL, DWLDE_LDE_CFG2, 0x1607); //LDE_CFG2 for 16MHz PRF
AndyA 3:1459d2aa6b97 168 else
AndyA 3:1459d2aa6b97 169 writeRegister16(DW1000_LDE_CTRL, DWLDE_LDE_CFG2, 0x0607); //LDE_CFG2 for 64MHz PRF
AndyA 3:1459d2aa6b97 170
AndyA 3:1459d2aa6b97 171 uint16_t replicaCoeff;
AndyA 4:5f1025df5530 172 switch (systemConfig.getPreambleCode()) {
AndyA 3:1459d2aa6b97 173 default:
AndyA 3:1459d2aa6b97 174 case 1:
AndyA 3:1459d2aa6b97 175 case 2:
AndyA 3:1459d2aa6b97 176 replicaCoeff = 0x5998;
AndyA 3:1459d2aa6b97 177 break;
AndyA 3:1459d2aa6b97 178 case 3:
AndyA 3:1459d2aa6b97 179 replicaCoeff = 0x51EA;
AndyA 3:1459d2aa6b97 180 break;
AndyA 3:1459d2aa6b97 181 case 4:
AndyA 3:1459d2aa6b97 182 replicaCoeff = 0x428E;
AndyA 3:1459d2aa6b97 183 break;
AndyA 3:1459d2aa6b97 184 case 5:
AndyA 3:1459d2aa6b97 185 replicaCoeff = 0x451E;
AndyA 3:1459d2aa6b97 186 break;
AndyA 3:1459d2aa6b97 187 case 6:
AndyA 3:1459d2aa6b97 188 replicaCoeff = 0x2E14;
AndyA 3:1459d2aa6b97 189 break;
AndyA 3:1459d2aa6b97 190 case 7:
AndyA 3:1459d2aa6b97 191 replicaCoeff = 0x8000;
AndyA 3:1459d2aa6b97 192 break;
AndyA 3:1459d2aa6b97 193 case 8:
AndyA 3:1459d2aa6b97 194 replicaCoeff = 0x51EA;
AndyA 3:1459d2aa6b97 195 break;
AndyA 3:1459d2aa6b97 196 case 9:
AndyA 3:1459d2aa6b97 197 replicaCoeff = 0x28F4;
AndyA 3:1459d2aa6b97 198 break;
AndyA 3:1459d2aa6b97 199 case 10:
AndyA 3:1459d2aa6b97 200 replicaCoeff = 0x3332;
AndyA 3:1459d2aa6b97 201 break;
AndyA 3:1459d2aa6b97 202 case 11:
AndyA 3:1459d2aa6b97 203 replicaCoeff = 0x3AE0;
AndyA 3:1459d2aa6b97 204 break;
AndyA 3:1459d2aa6b97 205 case 12:
AndyA 3:1459d2aa6b97 206 replicaCoeff = 0x3D70;
AndyA 3:1459d2aa6b97 207 break;
AndyA 3:1459d2aa6b97 208 case 13:
AndyA 3:1459d2aa6b97 209 replicaCoeff = 0x3AE0;
AndyA 3:1459d2aa6b97 210 break;
AndyA 3:1459d2aa6b97 211 case 14:
AndyA 3:1459d2aa6b97 212 replicaCoeff = 0x35C2;
AndyA 3:1459d2aa6b97 213 break;
AndyA 3:1459d2aa6b97 214 case 15:
AndyA 3:1459d2aa6b97 215 replicaCoeff = 0x2B84;
AndyA 3:1459d2aa6b97 216 break;
AndyA 3:1459d2aa6b97 217 case 16:
AndyA 3:1459d2aa6b97 218 replicaCoeff = 0x35C2;
AndyA 3:1459d2aa6b97 219 break;
AndyA 3:1459d2aa6b97 220 case 17:
AndyA 3:1459d2aa6b97 221 replicaCoeff = 0x3332;
AndyA 3:1459d2aa6b97 222 break;
AndyA 3:1459d2aa6b97 223 case 18:
AndyA 3:1459d2aa6b97 224 replicaCoeff = 0x35C2;
AndyA 3:1459d2aa6b97 225 break;
AndyA 3:1459d2aa6b97 226 case 19:
AndyA 3:1459d2aa6b97 227 replicaCoeff = 0x35C2;
AndyA 3:1459d2aa6b97 228 break;
AndyA 3:1459d2aa6b97 229 case 20:
AndyA 3:1459d2aa6b97 230 replicaCoeff = 0x47AE;
AndyA 3:1459d2aa6b97 231 break;
AndyA 3:1459d2aa6b97 232 case 21:
AndyA 3:1459d2aa6b97 233 replicaCoeff = 0x3AE0;
AndyA 3:1459d2aa6b97 234 break;
AndyA 3:1459d2aa6b97 235 case 22:
AndyA 3:1459d2aa6b97 236 replicaCoeff = 0x3850;
AndyA 3:1459d2aa6b97 237 break;
AndyA 3:1459d2aa6b97 238 case 23:
AndyA 3:1459d2aa6b97 239 replicaCoeff = 0x30A2;
AndyA 3:1459d2aa6b97 240 break;
AndyA 3:1459d2aa6b97 241 case 24:
AndyA 3:1459d2aa6b97 242 replicaCoeff = 0x3850;
AndyA 3:1459d2aa6b97 243 break;
AndyA 3:1459d2aa6b97 244 }
AndyA 3:1459d2aa6b97 245
AndyA 4:5f1025df5530 246 if (systemConfig.getDataRate() == DW1000Setup::kbps110)
AndyA 3:1459d2aa6b97 247 replicaCoeff = replicaCoeff>>3;
AndyA 3:1459d2aa6b97 248
AndyA 3:1459d2aa6b97 249 writeRegister16(DW1000_LDE_CTRL, DWLDE_LDE_REPC, replicaCoeff);
AndyA 3:1459d2aa6b97 250
AndyA 3:1459d2aa6b97 251 loadLDE();
AndyA 3:1459d2aa6b97 252 }
AndyA 3:1459d2aa6b97 253
AndyA 3:1459d2aa6b97 254 void DW1000::setupChannel()
AndyA 3:1459d2aa6b97 255 {
AndyA 4:5f1025df5530 256 uint32_t registerValue = 0;
AndyA 3:1459d2aa6b97 257
AndyA 4:5f1025df5530 258 registerValue = systemConfig.getChannel(); // set Tx channel
AndyA 4:5f1025df5530 259 registerValue |= systemConfig.getChannel()<<4; // set Rx channel
AndyA 3:1459d2aa6b97 260
AndyA 4:5f1025df5530 261 if (systemConfig.getPRF() == DW1000Setup::prf16MHz) // set PRF (2 bit value 01 or 10)
AndyA 3:1459d2aa6b97 262 registerValue |= 0x01 << 18;
AndyA 3:1459d2aa6b97 263 else
AndyA 3:1459d2aa6b97 264 registerValue |= 0x02 << 18;
AndyA 3:1459d2aa6b97 265
AndyA 8:0b408e77b701 266 if (systemConfig.getSfd() == DW1000Setup::decaWave)
AndyA 3:1459d2aa6b97 267 registerValue |= 0x01 << 17; // enable DW own SFD
AndyA 4:5f1025df5530 268
AndyA 8:0b408e77b701 269 if (systemConfig.getSfd() == DW1000Setup::user) {
AndyA 4:5f1025df5530 270 registerValue |= 0x01 << 20; // enable user set SFD Tx
AndyA 4:5f1025df5530 271 registerValue |= 0x01 << 21; // enable user set SFD Rx
AndyA 3:1459d2aa6b97 272 }
AndyA 3:1459d2aa6b97 273
AndyA 4:5f1025df5530 274 registerValue |= systemConfig.getPreambleCode() << 22; // set Tx preamble code
AndyA 4:5f1025df5530 275 registerValue |= systemConfig.getPreambleCode() << 27; // set Rx preamble code
AndyA 3:1459d2aa6b97 276
AndyA 4:5f1025df5530 277 writeRegister32(DW1000_CHAN_CTRL, 0, registerValue);
AndyA 3:1459d2aa6b97 278 }
AndyA 3:1459d2aa6b97 279
AndyA 3:1459d2aa6b97 280
AndyA 3:1459d2aa6b97 281 uint8_t DW1000::powerToRegValue(uint16_t powercB)
AndyA 3:1459d2aa6b97 282 {
AndyA 3:1459d2aa6b97 283
AndyA 3:1459d2aa6b97 284 // course power control - 0 = 18dB, 6 = 0dB in 3dB steps.
AndyA 3:1459d2aa6b97 285 uint8_t course = powercB / 30;
AndyA 3:1459d2aa6b97 286
AndyA 3:1459d2aa6b97 287 if(course > 6)
AndyA 3:1459d2aa6b97 288 course = 6;
AndyA 3:1459d2aa6b97 289
AndyA 3:1459d2aa6b97 290 // remaining power
AndyA 3:1459d2aa6b97 291 powercB -= course * 30;
AndyA 3:1459d2aa6b97 292
AndyA 3:1459d2aa6b97 293 // value in reg is inverse.
AndyA 3:1459d2aa6b97 294 course = 6-course;
AndyA 3:1459d2aa6b97 295
AndyA 3:1459d2aa6b97 296 // fine control in steps of 0.5dB
AndyA 3:1459d2aa6b97 297 uint8_t fine = powercB / 5;
AndyA 3:1459d2aa6b97 298 if (fine > 31)
AndyA 3:1459d2aa6b97 299 fine = 31;
AndyA 3:1459d2aa6b97 300
AndyA 3:1459d2aa6b97 301
AndyA 3:1459d2aa6b97 302 return (course << 5) | fine;
AndyA 3:1459d2aa6b97 303
AndyA 3:1459d2aa6b97 304 }
AndyA 3:1459d2aa6b97 305
AndyA 3:1459d2aa6b97 306 // transmit power: 0 to 33.5 dB gain in steps of 0.5. Inputs are in 10ths of a dB (0 to 335)
AndyA 3:1459d2aa6b97 307 void DW1000::setTxPower(uint16_t normalPowercB, uint16_t boost500, uint16_t boost250, uint16_t boost125)
AndyA 3:1459d2aa6b97 308 {
AndyA 4:5f1025df5530 309
AndyA 3:1459d2aa6b97 310 if(normalPowercB > 335)
AndyA 3:1459d2aa6b97 311 normalPowercB = 335;
AndyA 3:1459d2aa6b97 312
AndyA 3:1459d2aa6b97 313 if (boost500 < normalPowercB)
AndyA 3:1459d2aa6b97 314 boost500 = normalPowercB;
AndyA 3:1459d2aa6b97 315 if(boost500 > 335)
AndyA 3:1459d2aa6b97 316 boost500 = 335;
AndyA 0:bddb8cd5e7df 317
AndyA 3:1459d2aa6b97 318 if (boost250 < boost500)
AndyA 3:1459d2aa6b97 319 boost250 = boost500;
AndyA 3:1459d2aa6b97 320 if(boost250 > 335)
AndyA 3:1459d2aa6b97 321 boost250 = 335;
AndyA 3:1459d2aa6b97 322
AndyA 3:1459d2aa6b97 323 if (boost125 < boost250)
AndyA 3:1459d2aa6b97 324 boost125 = boost250;
AndyA 3:1459d2aa6b97 325 if(boost125 > 335)
AndyA 3:1459d2aa6b97 326 boost125 = 335;
AndyA 3:1459d2aa6b97 327
AndyA 4:5f1025df5530 328 if (systemConfig.getSmartPower() == false) {
AndyA 4:5f1025df5530 329 boost500 = normalPowercB;
AndyA 4:5f1025df5530 330 boost250 = normalPowercB;
AndyA 4:5f1025df5530 331 boost125 = normalPowercB;
AndyA 4:5f1025df5530 332 }
AndyA 4:5f1025df5530 333
AndyA 3:1459d2aa6b97 334 uint32_t powerReg = powerToRegValue(normalPowercB);
AndyA 3:1459d2aa6b97 335 powerReg |= powerToRegValue(boost500) << 8;
AndyA 3:1459d2aa6b97 336 powerReg |= powerToRegValue(boost250) << 16;
AndyA 3:1459d2aa6b97 337 powerReg |= powerToRegValue(boost125) << 24;
AndyA 8:0b408e77b701 338 writeRegister32(DW1000_TX_POWER, 0, powerReg);
AndyA 8:0b408e77b701 339
AndyA 3:1459d2aa6b97 340 }
AndyA 3:1459d2aa6b97 341
AndyA 3:1459d2aa6b97 342 void DW1000::setupAnalogRF()
AndyA 3:1459d2aa6b97 343 {
AndyA 4:5f1025df5530 344 switch (systemConfig.getChannel()) {
AndyA 3:1459d2aa6b97 345 case 1:
AndyA 3:1459d2aa6b97 346 writeRegister32(DW1000_RF_CONF, DWRFCONF_RF_TXCTRL, 0x00005C40);
AndyA 3:1459d2aa6b97 347 break;
AndyA 3:1459d2aa6b97 348 case 2:
AndyA 3:1459d2aa6b97 349 writeRegister32(DW1000_RF_CONF, DWRFCONF_RF_TXCTRL, 0x00045CA0);
AndyA 3:1459d2aa6b97 350 break;
AndyA 3:1459d2aa6b97 351 case 3:
AndyA 3:1459d2aa6b97 352 writeRegister32(DW1000_RF_CONF, DWRFCONF_RF_TXCTRL, 0x00086CC0);
AndyA 3:1459d2aa6b97 353 break;
AndyA 3:1459d2aa6b97 354 case 4:
AndyA 3:1459d2aa6b97 355 writeRegister32(DW1000_RF_CONF, DWRFCONF_RF_TXCTRL, 0x00045C80);
AndyA 3:1459d2aa6b97 356 break;
AndyA 3:1459d2aa6b97 357 case 5:
AndyA 3:1459d2aa6b97 358 default:
AndyA 3:1459d2aa6b97 359 writeRegister32(DW1000_RF_CONF, DWRFCONF_RF_TXCTRL, 0x001E3FE0);
AndyA 3:1459d2aa6b97 360 break;
AndyA 3:1459d2aa6b97 361 case 7:
AndyA 3:1459d2aa6b97 362 writeRegister32(DW1000_RF_CONF, DWRFCONF_RF_TXCTRL, 0x001E7DE0);
AndyA 3:1459d2aa6b97 363 break;
AndyA 3:1459d2aa6b97 364 }
AndyA 3:1459d2aa6b97 365
AndyA 4:5f1025df5530 366 switch (systemConfig.getChannel()) {
AndyA 3:1459d2aa6b97 367 case 1:
AndyA 3:1459d2aa6b97 368 case 2:
AndyA 3:1459d2aa6b97 369 case 3:
AndyA 3:1459d2aa6b97 370 case 5:
AndyA 3:1459d2aa6b97 371 default:
AndyA 3:1459d2aa6b97 372 writeRegister8(DW1000_RF_CONF, DWRFCONF_RF_RXCTRLH, 0xD8);
AndyA 3:1459d2aa6b97 373 break;
AndyA 3:1459d2aa6b97 374 case 4:
AndyA 3:1459d2aa6b97 375 case 7:
AndyA 3:1459d2aa6b97 376 writeRegister8(DW1000_RF_CONF, DWRFCONF_RF_RXCTRLH, 0xBC);
AndyA 3:1459d2aa6b97 377 break;
AndyA 3:1459d2aa6b97 378 }
AndyA 3:1459d2aa6b97 379
AndyA 3:1459d2aa6b97 380 loadLDOTUNE();
AndyA 3:1459d2aa6b97 381
AndyA 3:1459d2aa6b97 382 }
AndyA 3:1459d2aa6b97 383
AndyA 3:1459d2aa6b97 384 void DW1000::setupTxCalibration()
AndyA 3:1459d2aa6b97 385 {
AndyA 4:5f1025df5530 386 switch (systemConfig.getChannel()) {
AndyA 3:1459d2aa6b97 387 case 1:
AndyA 3:1459d2aa6b97 388 writeRegister8 (DW1000_TX_CAL, DWTXCAL_TC_PGDELAY, 0xC9);
AndyA 3:1459d2aa6b97 389 break;
AndyA 3:1459d2aa6b97 390 case 2:
AndyA 3:1459d2aa6b97 391 writeRegister8 (DW1000_TX_CAL, DWTXCAL_TC_PGDELAY, 0xC2);
AndyA 3:1459d2aa6b97 392 break;
AndyA 3:1459d2aa6b97 393 case 3:
AndyA 3:1459d2aa6b97 394 writeRegister8 (DW1000_TX_CAL, DWTXCAL_TC_PGDELAY, 0xC5);
AndyA 3:1459d2aa6b97 395 break;
AndyA 3:1459d2aa6b97 396 case 4:
AndyA 3:1459d2aa6b97 397 writeRegister8 (DW1000_TX_CAL, DWTXCAL_TC_PGDELAY, 0x95);
AndyA 3:1459d2aa6b97 398 break;
AndyA 3:1459d2aa6b97 399 case 5:
AndyA 3:1459d2aa6b97 400 default:
AndyA 3:1459d2aa6b97 401 writeRegister8 (DW1000_TX_CAL, DWTXCAL_TC_PGDELAY, 0xC0);
AndyA 3:1459d2aa6b97 402 break;
AndyA 3:1459d2aa6b97 403 case 7:
AndyA 3:1459d2aa6b97 404 writeRegister8 (DW1000_TX_CAL, DWTXCAL_TC_PGDELAY, 0x93);
AndyA 3:1459d2aa6b97 405 break;
AndyA 3:1459d2aa6b97 406 }
AndyA 3:1459d2aa6b97 407 }
AndyA 3:1459d2aa6b97 408
AndyA 3:1459d2aa6b97 409 void DW1000::setupFreqSynth()
AndyA 3:1459d2aa6b97 410 {
AndyA 3:1459d2aa6b97 411
AndyA 4:5f1025df5530 412 switch (systemConfig.getChannel()) {
AndyA 3:1459d2aa6b97 413 case 1:
AndyA 3:1459d2aa6b97 414 writeRegister32 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLCFG, 0x09000407); //FS_PLLCFG for channel 1
AndyA 3:1459d2aa6b97 415 writeRegister8 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLTUNE, 0x1E);
AndyA 3:1459d2aa6b97 416 break;
AndyA 3:1459d2aa6b97 417 case 2:
AndyA 3:1459d2aa6b97 418 case 4:
AndyA 3:1459d2aa6b97 419 writeRegister32 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLCFG, 0x08400508); //FS_PLLCFG for channel 2,4
AndyA 3:1459d2aa6b97 420 writeRegister8 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLTUNE, 0x26);
AndyA 3:1459d2aa6b97 421 break;
AndyA 3:1459d2aa6b97 422 case 3:
AndyA 3:1459d2aa6b97 423 writeRegister32 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLCFG, 0x08401009); //FS_PLLCFG for channel 3
AndyA 3:1459d2aa6b97 424 writeRegister8 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLTUNE, 0x5E);
AndyA 3:1459d2aa6b97 425 break;
AndyA 3:1459d2aa6b97 426 case 5:
AndyA 3:1459d2aa6b97 427 case 7:
AndyA 3:1459d2aa6b97 428 default:
AndyA 3:1459d2aa6b97 429 writeRegister32 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLCFG, 0x0800041D); //FS_PLLCFG for channel 5,7
AndyA 3:1459d2aa6b97 430 writeRegister8 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLTUNE, 0xBE); //FS_PLLTUNE for channel 5
AndyA 3:1459d2aa6b97 431 break;
AndyA 3:1459d2aa6b97 432 }
AndyA 3:1459d2aa6b97 433 }
AndyA 3:1459d2aa6b97 434
AndyA 3:1459d2aa6b97 435 void DW1000::setupTxFrameCtrl()
AndyA 3:1459d2aa6b97 436 {
AndyA 4:5f1025df5530 437 uint32_t frameCtrlValue = 0;
AndyA 4:5f1025df5530 438 switch (systemConfig.getDataRate()) {
AndyA 4:5f1025df5530 439 case DW1000Setup::kbps110:
AndyA 3:1459d2aa6b97 440 break;
AndyA 4:5f1025df5530 441 case DW1000Setup::kbps850:
AndyA 3:1459d2aa6b97 442 frameCtrlValue |= 0x01<<13;
AndyA 3:1459d2aa6b97 443 break;
AndyA 4:5f1025df5530 444 case DW1000Setup::kbps6800:
AndyA 3:1459d2aa6b97 445 default:
AndyA 3:1459d2aa6b97 446 frameCtrlValue |= 0x02<<13;
AndyA 3:1459d2aa6b97 447 break;
AndyA 3:1459d2aa6b97 448 }
AndyA 3:1459d2aa6b97 449 frameCtrlValue |= 0x01<<15;
AndyA 3:1459d2aa6b97 450
AndyA 4:5f1025df5530 451 if (systemConfig.getPRF() == DW1000Setup::prf16MHz)
AndyA 3:1459d2aa6b97 452 frameCtrlValue |= 0x01<<16;
AndyA 3:1459d2aa6b97 453 else
AndyA 3:1459d2aa6b97 454 frameCtrlValue |= 0x02<<16;
AndyA 3:1459d2aa6b97 455
AndyA 4:5f1025df5530 456 switch (systemConfig.getPreambleLength()) {
AndyA 4:5f1025df5530 457 case DW1000Setup::pre64:
AndyA 3:1459d2aa6b97 458 frameCtrlValue |= 0x01<<18; // TXPSR
AndyA 3:1459d2aa6b97 459 frameCtrlValue |= 0x00<<20; // PE
AndyA 3:1459d2aa6b97 460 break;
AndyA 4:5f1025df5530 461 case DW1000Setup::pre128:
AndyA 3:1459d2aa6b97 462 default:
AndyA 3:1459d2aa6b97 463 frameCtrlValue |= 0x01<<18; // TXPSR
AndyA 3:1459d2aa6b97 464 frameCtrlValue |= 0x01<<20; // PE
AndyA 3:1459d2aa6b97 465 break;
AndyA 4:5f1025df5530 466 case DW1000Setup::pre256:
AndyA 3:1459d2aa6b97 467 frameCtrlValue |= 0x01<<18; // TXPSR
AndyA 3:1459d2aa6b97 468 frameCtrlValue |= 0x02<<20; // PE
AndyA 3:1459d2aa6b97 469 break;
AndyA 4:5f1025df5530 470 case DW1000Setup::pre512:
AndyA 3:1459d2aa6b97 471 frameCtrlValue |= 0x01<<18; // TXPSR
AndyA 3:1459d2aa6b97 472 frameCtrlValue |= 0x03<<20; // PE
AndyA 3:1459d2aa6b97 473 break;
AndyA 4:5f1025df5530 474 case DW1000Setup::pre1024:
AndyA 3:1459d2aa6b97 475 frameCtrlValue |= 0x02<<18; // TXPSR
AndyA 3:1459d2aa6b97 476 frameCtrlValue |= 0x00<<20; // PE
AndyA 3:1459d2aa6b97 477 break;
AndyA 4:5f1025df5530 478 case DW1000Setup::pre1536:
AndyA 3:1459d2aa6b97 479 frameCtrlValue |= 0x02<<18; // TXPSR
AndyA 3:1459d2aa6b97 480 frameCtrlValue |= 0x01<<20; // PE
AndyA 3:1459d2aa6b97 481 break;
AndyA 4:5f1025df5530 482 case DW1000Setup::pre2048:
AndyA 3:1459d2aa6b97 483 frameCtrlValue |= 0x02<<18; // TXPSR
AndyA 3:1459d2aa6b97 484 frameCtrlValue |= 0x02<<20; // PE
AndyA 3:1459d2aa6b97 485 break;
AndyA 4:5f1025df5530 486 case DW1000Setup::pre4096:
AndyA 3:1459d2aa6b97 487 frameCtrlValue |= 0x03<<18; // TXPSR
AndyA 3:1459d2aa6b97 488 frameCtrlValue |= 0x00<<20; // PE
AndyA 3:1459d2aa6b97 489 break;
AndyA 3:1459d2aa6b97 490 }
AndyA 4:5f1025df5530 491 writeRegister32(DW1000_TX_FCTRL,0,frameCtrlValue);
AndyA 0:bddb8cd5e7df 492 }
AndyA 0:bddb8cd5e7df 493
AndyA 0:bddb8cd5e7df 494 void DW1000::setRxDelay(uint16_t ticks)
AndyA 0:bddb8cd5e7df 495 {
AndyA 0:bddb8cd5e7df 496 writeRegister16(DW1000_LDE_CTRL, DWLDE_LDE_RXANTD, ticks);
AndyA 0:bddb8cd5e7df 497 }
AndyA 0:bddb8cd5e7df 498 void DW1000::setTxDelay(uint16_t ticks)
AndyA 0:bddb8cd5e7df 499 {
AndyA 0:bddb8cd5e7df 500 writeRegister16(DW1000_TX_ANTD, 0, ticks);
AndyA 0:bddb8cd5e7df 501 }
AndyA 0:bddb8cd5e7df 502
AndyA 0:bddb8cd5e7df 503 void DW1000::setCallbacks(void (*callbackRX)(void), void (*callbackTX)(void))
AndyA 0:bddb8cd5e7df 504 {
AndyA 0:bddb8cd5e7df 505 bool RX = false;
AndyA 0:bddb8cd5e7df 506 bool TX = false;
AndyA 0:bddb8cd5e7df 507 if (callbackRX) {
AndyA 0:bddb8cd5e7df 508 DW1000::callbackRX.attach(callbackRX);
AndyA 0:bddb8cd5e7df 509 RX = true;
AndyA 0:bddb8cd5e7df 510 }
AndyA 0:bddb8cd5e7df 511 if (callbackTX) {
AndyA 0:bddb8cd5e7df 512 DW1000::callbackTX.attach(callbackTX);
AndyA 0:bddb8cd5e7df 513 TX = true;
AndyA 0:bddb8cd5e7df 514 }
AndyA 0:bddb8cd5e7df 515 setInterrupt(RX,TX);
AndyA 0:bddb8cd5e7df 516 }
AndyA 0:bddb8cd5e7df 517
AndyA 0:bddb8cd5e7df 518 uint32_t DW1000::getDeviceID()
AndyA 0:bddb8cd5e7df 519 {
AndyA 0:bddb8cd5e7df 520 uint32_t result;
AndyA 0:bddb8cd5e7df 521 readRegister(DW1000_DEV_ID, 0, (uint8_t*)&result, 4);
AndyA 0:bddb8cd5e7df 522 return result;
AndyA 0:bddb8cd5e7df 523 }
AndyA 0:bddb8cd5e7df 524
AndyA 0:bddb8cd5e7df 525 uint64_t DW1000::getEUI()
AndyA 0:bddb8cd5e7df 526 {
AndyA 0:bddb8cd5e7df 527 uint64_t result;
AndyA 0:bddb8cd5e7df 528 readRegister(DW1000_EUI, 0, (uint8_t*)&result, 8);
AndyA 0:bddb8cd5e7df 529 return result;
AndyA 0:bddb8cd5e7df 530 }
AndyA 0:bddb8cd5e7df 531
AndyA 0:bddb8cd5e7df 532 void DW1000::setEUI(uint64_t EUI)
AndyA 0:bddb8cd5e7df 533 {
AndyA 0:bddb8cd5e7df 534 writeRegister(DW1000_EUI, 0, (uint8_t*)&EUI, 8);
AndyA 0:bddb8cd5e7df 535 }
AndyA 0:bddb8cd5e7df 536
AndyA 0:bddb8cd5e7df 537
AndyA 0:bddb8cd5e7df 538 float DW1000::getVoltage()
AndyA 0:bddb8cd5e7df 539 {
AndyA 0:bddb8cd5e7df 540 uint8_t data;
AndyA 0:bddb8cd5e7df 541
AndyA 0:bddb8cd5e7df 542 writeRegister8(DW1000_RF_CONF, 0x11, 0x80);
AndyA 0:bddb8cd5e7df 543 writeRegister8(DW1000_RF_CONF, 0x12, 0x0A);
AndyA 0:bddb8cd5e7df 544 writeRegister8(DW1000_RF_CONF, 0x12, 0x0F);
AndyA 0:bddb8cd5e7df 545 writeRegister8(DW1000_TX_CAL, 0x00, 0x01);
AndyA 0:bddb8cd5e7df 546 writeRegister8(DW1000_TX_CAL, 0x00, 0x00);
AndyA 0:bddb8cd5e7df 547 data = readRegister8(DW1000_TX_CAL, 0x03); // get the 8-Bit reading for Voltage
AndyA 1:dcbd071f38d5 548 float Voltage = (float)(data - (readOTP(0x08)&0x00ff)) *0.00578 + 3.3;
AndyA 0:bddb8cd5e7df 549 return Voltage;
AndyA 0:bddb8cd5e7df 550 }
AndyA 0:bddb8cd5e7df 551
AndyA 0:bddb8cd5e7df 552 float DW1000::getTemperature()
AndyA 0:bddb8cd5e7df 553 {
AndyA 0:bddb8cd5e7df 554 uint8_t data;
AndyA 0:bddb8cd5e7df 555
AndyA 0:bddb8cd5e7df 556 writeRegister8(DW1000_RF_CONF, 0x11, 0x80);
AndyA 0:bddb8cd5e7df 557 writeRegister8(DW1000_RF_CONF, 0x12, 0x0A);
AndyA 0:bddb8cd5e7df 558 writeRegister8(DW1000_RF_CONF, 0x12, 0x0F);
AndyA 0:bddb8cd5e7df 559 writeRegister8(DW1000_TX_CAL, 0x00, 0x01);
AndyA 0:bddb8cd5e7df 560 writeRegister8(DW1000_TX_CAL, 0x00, 0x00);
AndyA 0:bddb8cd5e7df 561 data = readRegister16(DW1000_TX_CAL, 0x04); // get the 8-Bit reading for Temperature
AndyA 1:dcbd071f38d5 562 float temperature = (float)(data - (readOTP(0x09) & 0x00ff))*0.9 + 23;
AndyA 0:bddb8cd5e7df 563 return temperature;
AndyA 0:bddb8cd5e7df 564 }
AndyA 0:bddb8cd5e7df 565
AndyA 0:bddb8cd5e7df 566
AndyA 0:bddb8cd5e7df 567 uint64_t DW1000::getStatus()
AndyA 0:bddb8cd5e7df 568 {
AndyA 0:bddb8cd5e7df 569 return readRegister40(DW1000_SYS_STATUS, 0);
AndyA 0:bddb8cd5e7df 570 }
AndyA 0:bddb8cd5e7df 571
AndyA 0:bddb8cd5e7df 572 uint64_t DW1000::getRXTimestamp()
AndyA 0:bddb8cd5e7df 573 {
AndyA 0:bddb8cd5e7df 574 return readRegister40(DW1000_RX_TIME, 0);
AndyA 0:bddb8cd5e7df 575 }
AndyA 0:bddb8cd5e7df 576
AndyA 0:bddb8cd5e7df 577 uint64_t DW1000::getTXTimestamp()
AndyA 0:bddb8cd5e7df 578 {
AndyA 0:bddb8cd5e7df 579 return readRegister40(DW1000_TX_TIME, 0);
AndyA 0:bddb8cd5e7df 580 }
AndyA 0:bddb8cd5e7df 581
AndyA 0:bddb8cd5e7df 582
AndyA 0:bddb8cd5e7df 583 void DW1000::sendFrame(uint8_t* message, uint16_t length)
AndyA 0:bddb8cd5e7df 584 {
AndyA 0:bddb8cd5e7df 585 //if (length >= 1021) length = 1021; // check for maximim length a frame can have with 1024 Byte frames [not used, see constructor]
AndyA 0:bddb8cd5e7df 586 if (length >= 125) length = 125; // check for maximim length a frame can have with 127 Byte frames
AndyA 0:bddb8cd5e7df 587 uint8_t len_7bit = length;
AndyA 0:bddb8cd5e7df 588 writeRegister(DW1000_TX_BUFFER, 0, message, len_7bit); // fill buffer
AndyA 0:bddb8cd5e7df 589
AndyA 3:1459d2aa6b97 590 /* support for frames over 127 bytes
AndyA 3:1459d2aa6b97 591 uint8_t backup = readRegister8(DW1000_TX_FCTRL, 1); // put length of frame
AndyA 3:1459d2aa6b97 592 length += 2; // including 2 CRC Bytes
AndyA 3:1459d2aa6b97 593 length = ((backup & 0xFC) << 8) | (length & 0x03FF);
AndyA 3:1459d2aa6b97 594 writeRegister16(DW1000_TX_FCTRL, 0, length);
AndyA 3:1459d2aa6b97 595 */
AndyA 0:bddb8cd5e7df 596 len_7bit += 2; // including 2 CRC Bytes
AndyA 0:bddb8cd5e7df 597 writeRegister8(DW1000_TX_FCTRL, 0, len_7bit);
AndyA 0:bddb8cd5e7df 598
AndyA 0:bddb8cd5e7df 599 stopTRX(); // stop receiving
AndyA 0:bddb8cd5e7df 600 writeRegister8(DW1000_SYS_CTRL, 0, 0x02 | 0x80); // trigger sending process by setting the TXSTRT bit
AndyA 0:bddb8cd5e7df 601 // startRX(); // enable receiver again
AndyA 0:bddb8cd5e7df 602 }
AndyA 0:bddb8cd5e7df 603
AndyA 3:1459d2aa6b97 604 void DW1000::setupSyncedFrame(uint8_t* message, uint16_t length)
AndyA 3:1459d2aa6b97 605 {
AndyA 0:bddb8cd5e7df 606 //if (length >= 1021) length = 1021; // check for maximim length a frame can have with 1024 Byte frames [not used, see constructor]
AndyA 0:bddb8cd5e7df 607 if (length >= 125) length = 125; // check for maximim length a frame can have with 127 Byte frames
AndyA 0:bddb8cd5e7df 608 writeRegister(DW1000_TX_BUFFER, 0, message, length); // fill buffer
AndyA 0:bddb8cd5e7df 609
AndyA 0:bddb8cd5e7df 610 uint8_t backup = readRegister8(DW1000_TX_FCTRL, 1); // put length of frame
AndyA 0:bddb8cd5e7df 611 length += 2; // including 2 CRC Bytes
AndyA 0:bddb8cd5e7df 612 length = ((backup & 0xFC) << 8) | (length & 0x03FF);
AndyA 0:bddb8cd5e7df 613 writeRegister16(DW1000_TX_FCTRL, 0, length);
AndyA 0:bddb8cd5e7df 614 }
AndyA 0:bddb8cd5e7df 615
AndyA 3:1459d2aa6b97 616 void DW1000::armSyncedFrame()
AndyA 3:1459d2aa6b97 617 {
AndyA 0:bddb8cd5e7df 618 stopTRX(); // stop receiving
AndyA 0:bddb8cd5e7df 619 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 3:1459d2aa6b97 620 }
AndyA 0:bddb8cd5e7df 621
AndyA 0:bddb8cd5e7df 622 void DW1000::sendDelayedFrame(uint8_t* message, uint16_t length, uint64_t TxTimestamp)
AndyA 0:bddb8cd5e7df 623 {
AndyA 0:bddb8cd5e7df 624 //if (length >= 1021) length = 1021; // check for maximim length a frame can have with 1024 Byte frames [not used, see constructor]
AndyA 0:bddb8cd5e7df 625 if (length >= 125) length = 125; // check for maximim length a frame can have with 127 Byte frames
AndyA 0:bddb8cd5e7df 626 writeRegister(DW1000_TX_BUFFER, 0, message, length); // fill buffer
AndyA 0:bddb8cd5e7df 627
AndyA 0:bddb8cd5e7df 628 uint8_t backup = readRegister8(DW1000_TX_FCTRL, 1); // put length of frame
AndyA 0:bddb8cd5e7df 629 length += 2; // including 2 CRC Bytes
AndyA 0:bddb8cd5e7df 630 length = ((backup & 0xFC) << 8) | (length & 0x03FF);
AndyA 0:bddb8cd5e7df 631 writeRegister16(DW1000_TX_FCTRL, 0, length);
AndyA 0:bddb8cd5e7df 632
AndyA 0:bddb8cd5e7df 633 writeRegister40(DW1000_DX_TIME, 0, TxTimestamp); //write the timestamp on which to send the message
AndyA 0:bddb8cd5e7df 634
AndyA 0:bddb8cd5e7df 635 stopTRX(); // stop receiving
AndyA 0:bddb8cd5e7df 636 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 637 }
AndyA 0:bddb8cd5e7df 638
AndyA 0:bddb8cd5e7df 639 void DW1000::startRX()
AndyA 0:bddb8cd5e7df 640 {
AndyA 0:bddb8cd5e7df 641 writeRegister8(DW1000_SYS_CTRL, 0x01, 0x01); // start listening for preamble by setting the RXENAB bit
AndyA 0:bddb8cd5e7df 642 }
AndyA 0:bddb8cd5e7df 643
AndyA 0:bddb8cd5e7df 644 void DW1000::stopTRX()
AndyA 0:bddb8cd5e7df 645 {
AndyA 0:bddb8cd5e7df 646 writeRegister8(DW1000_SYS_CTRL, 0, 0x40); // disable tranceiver go back to idle mode
AndyA 0:bddb8cd5e7df 647 }
AndyA 0:bddb8cd5e7df 648
AndyA 0:bddb8cd5e7df 649 // PRIVATE Methods ------------------------------------------------------------------------------------
AndyA 0:bddb8cd5e7df 650 void DW1000::loadLDE() // initialise LDE algorithm LDELOAD User Manual p22
AndyA 0:bddb8cd5e7df 651 {
AndyA 0:bddb8cd5e7df 652 spi.frequency(SPIRATE_OSC); // with a 1MHz clock rate (worked up to 49MHz in our Test)
AndyA 0:bddb8cd5e7df 653
AndyA 0:bddb8cd5e7df 654 writeRegister16(DW1000_PMSC, 0, 0x0301); // set clock to XTAL so OTP is reliable
AndyA 0:bddb8cd5e7df 655 writeRegister16(DW1000_OTP_IF, DWOTP_OTP_CTRL, 0x8000); // set LDELOAD bit in OTP
AndyA 0:bddb8cd5e7df 656 wait_us(150);
AndyA 0:bddb8cd5e7df 657 writeRegister16(DW1000_PMSC, 0, 0x0200); // recover to PLL clock
AndyA 0:bddb8cd5e7df 658
AndyA 0:bddb8cd5e7df 659 wait_ms(1);
AndyA 0:bddb8cd5e7df 660
AndyA 0:bddb8cd5e7df 661 spi.frequency(SPIRATE_PLL); // with a 1MHz clock rate (worked up to 49MHz in our Test)
AndyA 0:bddb8cd5e7df 662
AndyA 0:bddb8cd5e7df 663 }
AndyA 0:bddb8cd5e7df 664
AndyA 0:bddb8cd5e7df 665 void DW1000::loadLDOTUNE()
AndyA 0:bddb8cd5e7df 666 {
AndyA 1:dcbd071f38d5 667 uint64_t LDOTuningValue = readOTP(0x0004);
AndyA 1:dcbd071f38d5 668 if (LDOTuningValue != 0) {
AndyA 1:dcbd071f38d5 669 LDOTuningValue = LDOTuningValue | ((uint64_t)(readOTP(0x0005) & 0x00ff) << 32);
AndyA 0:bddb8cd5e7df 670 writeRegister40(DW1000_RF_CONF,DWRFCONF_RF_LDOTUNE,LDOTuningValue);
AndyA 1:dcbd071f38d5 671 }
AndyA 0:bddb8cd5e7df 672 }
AndyA 0:bddb8cd5e7df 673
AndyA 0:bddb8cd5e7df 674 void DW1000::resetRX()
AndyA 0:bddb8cd5e7df 675 {
AndyA 0:bddb8cd5e7df 676 writeRegister8(DW1000_PMSC, 3, 0xE0); // set RX reset
AndyA 0:bddb8cd5e7df 677 writeRegister8(DW1000_PMSC, 3, 0xF0); // clear RX reset
AndyA 0:bddb8cd5e7df 678 }
AndyA 0:bddb8cd5e7df 679
AndyA 0:bddb8cd5e7df 680 void DW1000::resetAll()
AndyA 0:bddb8cd5e7df 681 {
AndyA 0:bddb8cd5e7df 682 spi.frequency(SPIRATE_OSC); // with a 1MHz clock rate (worked up to 49MHz in our Test)
AndyA 0:bddb8cd5e7df 683
AndyA 0:bddb8cd5e7df 684 writeRegister8(DW1000_PMSC, 0, 0x01); // set clock to XTAL
AndyA 0:bddb8cd5e7df 685 writeRegister8(DW1000_PMSC, 3, 0x00); // set All reset
AndyA 0:bddb8cd5e7df 686 wait_us(10); // wait for PLL to lock
AndyA 0:bddb8cd5e7df 687 writeRegister8(DW1000_PMSC, 3, 0xF0); // clear All reset
AndyA 0:bddb8cd5e7df 688
AndyA 0:bddb8cd5e7df 689 wait_ms(1);
AndyA 0:bddb8cd5e7df 690
AndyA 0:bddb8cd5e7df 691 spi.frequency(SPIRATE_PLL); // with a 1MHz clock rate (worked up to 49MHz in our Test)
AndyA 0:bddb8cd5e7df 692 }
AndyA 0:bddb8cd5e7df 693
AndyA 0:bddb8cd5e7df 694 /// After writes have been completed reset the device.
AndyA 1:dcbd071f38d5 695 bool DW1000::writeOTP(uint16_t word_address,uint32_t data)
AndyA 0:bddb8cd5e7df 696 {
AndyA 0:bddb8cd5e7df 697 spi.frequency(SPIRATE_OSC); // with a 1MHz clock rate (worked up to 49MHz in our Test)
AndyA 0:bddb8cd5e7df 698
AndyA 0:bddb8cd5e7df 699 writeRegister8(DW1000_PMSC, 0, 0x01); // set clock to XTAL
AndyA 0:bddb8cd5e7df 700 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x03); //
AndyA 0:bddb8cd5e7df 701 writeRegister16(DW1000_OTP_IF,DWOTP_OTP_WDAT,0x9220); //
AndyA 0:bddb8cd5e7df 702 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x08); //
AndyA 0:bddb8cd5e7df 703 wait_ms(1);
AndyA 0:bddb8cd5e7df 704 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x02); //
AndyA 0:bddb8cd5e7df 705 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x88); //
AndyA 0:bddb8cd5e7df 706 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x80); //
AndyA 0:bddb8cd5e7df 707 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00); //
AndyA 0:bddb8cd5e7df 708
AndyA 0:bddb8cd5e7df 709 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x05); //
AndyA 0:bddb8cd5e7df 710 writeRegister16(DW1000_OTP_IF,DWOTP_OTP_WDAT,0x000E); //
AndyA 0:bddb8cd5e7df 711 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x08); //
AndyA 0:bddb8cd5e7df 712 wait_ms(1);
AndyA 0:bddb8cd5e7df 713 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x04); //
AndyA 0:bddb8cd5e7df 714 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x88); //
AndyA 0:bddb8cd5e7df 715 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x80); //
AndyA 0:bddb8cd5e7df 716 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00); //
AndyA 0:bddb8cd5e7df 717
AndyA 0:bddb8cd5e7df 718 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x01); //
AndyA 0:bddb8cd5e7df 719 writeRegister16(DW1000_OTP_IF,DWOTP_OTP_WDAT,0x1024); //
AndyA 0:bddb8cd5e7df 720 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x08); //
AndyA 0:bddb8cd5e7df 721 wait_ms(1);
AndyA 0:bddb8cd5e7df 722 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x00); //
AndyA 0:bddb8cd5e7df 723
AndyA 0:bddb8cd5e7df 724 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00); //
AndyA 0:bddb8cd5e7df 725 writeRegister32(DW1000_OTP_IF,DWOTP_OTP_WDAT,data); //
AndyA 1:dcbd071f38d5 726 writeRegister16(DW1000_OTP_IF,DWOTP_OTP_ADDR,word_address); //
AndyA 0:bddb8cd5e7df 727 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x40); //
AndyA 0:bddb8cd5e7df 728 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00); //
AndyA 0:bddb8cd5e7df 729 wait_ms(1);
AndyA 0:bddb8cd5e7df 730
AndyA 0:bddb8cd5e7df 731 for (int i=0; i<10; i++) {
AndyA 1:dcbd071f38d5 732 if (readOTP(word_address) == data)
AndyA 0:bddb8cd5e7df 733 return true;
AndyA 0:bddb8cd5e7df 734 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x40); // retry
AndyA 0:bddb8cd5e7df 735 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00);
AndyA 0:bddb8cd5e7df 736 wait_ms(1);
AndyA 0:bddb8cd5e7df 737 }
AndyA 0:bddb8cd5e7df 738 return false;
AndyA 0:bddb8cd5e7df 739 }
AndyA 0:bddb8cd5e7df 740
AndyA 0:bddb8cd5e7df 741
AndyA 1:dcbd071f38d5 742 uint32_t DW1000::readOTP(uint16_t word_address)
AndyA 0:bddb8cd5e7df 743 {
AndyA 1:dcbd071f38d5 744 writeRegister16(DW1000_OTP_IF,DWOTP_OTP_ADDR,word_address); // write address
AndyA 0:bddb8cd5e7df 745 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x03); // read address load
AndyA 0:bddb8cd5e7df 746 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x01); // read
AndyA 0:bddb8cd5e7df 747 uint32_t data = readRegister32(DW1000_OTP_IF,DWOTP_OTP_RDAT);
AndyA 0:bddb8cd5e7df 748 writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00); // OTP idle
AndyA 0:bddb8cd5e7df 749 return data;
AndyA 0:bddb8cd5e7df 750 }
AndyA 0:bddb8cd5e7df 751
AndyA 0:bddb8cd5e7df 752 void DW1000::setInterrupt(bool RX, bool TX)
AndyA 0:bddb8cd5e7df 753 {
AndyA 0:bddb8cd5e7df 754 writeRegister16(DW1000_SYS_MASK, 0, RX*0x4000 | TX*0x0080); // RX good frame 0x4000, TX done 0x0080
AndyA 0:bddb8cd5e7df 755 }
AndyA 0:bddb8cd5e7df 756
AndyA 0:bddb8cd5e7df 757 void DW1000::ISR()
AndyA 0:bddb8cd5e7df 758 {
AndyA 0:bddb8cd5e7df 759 uint64_t status = getStatus();
AndyA 0:bddb8cd5e7df 760 if (status & 0x4000) { // a frame was received
AndyA 0:bddb8cd5e7df 761 callbackRX.call();
AndyA 0:bddb8cd5e7df 762 writeRegister16(DW1000_SYS_STATUS, 0, 0x6F00); // clearing of receiving status bits
AndyA 0:bddb8cd5e7df 763 }
AndyA 0:bddb8cd5e7df 764 if (status & 0x80) { // sending complete
AndyA 0:bddb8cd5e7df 765 callbackTX.call();
AndyA 0:bddb8cd5e7df 766 writeRegister8(DW1000_SYS_STATUS, 0, 0xF8); // clearing of sending status bits
AndyA 0:bddb8cd5e7df 767 }
AndyA 0:bddb8cd5e7df 768 }
AndyA 0:bddb8cd5e7df 769
AndyA 0:bddb8cd5e7df 770 uint16_t DW1000::getFramelength()
AndyA 0:bddb8cd5e7df 771 {
AndyA 0:bddb8cd5e7df 772 uint16_t framelength = readRegister16(DW1000_RX_FINFO, 0); // get framelength
AndyA 0:bddb8cd5e7df 773 framelength = (framelength & 0x03FF) - 2; // take only the right bits and subtract the 2 CRC Bytes
AndyA 0:bddb8cd5e7df 774 return framelength;
AndyA 0:bddb8cd5e7df 775 }
AndyA 0:bddb8cd5e7df 776
AndyA 0:bddb8cd5e7df 777 // SPI Interface ------------------------------------------------------------------------------------
AndyA 0:bddb8cd5e7df 778 uint8_t DW1000::readRegister8(uint8_t reg, uint16_t subaddress)
AndyA 0:bddb8cd5e7df 779 {
AndyA 0:bddb8cd5e7df 780 uint8_t result;
AndyA 0:bddb8cd5e7df 781 readRegister(reg, subaddress, &result, 1);
AndyA 0:bddb8cd5e7df 782 return result;
AndyA 0:bddb8cd5e7df 783 }
AndyA 0:bddb8cd5e7df 784
AndyA 0:bddb8cd5e7df 785 uint16_t DW1000::readRegister16(uint8_t reg, uint16_t subaddress)
AndyA 0:bddb8cd5e7df 786 {
AndyA 0:bddb8cd5e7df 787 uint16_t result;
AndyA 0:bddb8cd5e7df 788 readRegister(reg, subaddress, (uint8_t*)&result, 2);
AndyA 0:bddb8cd5e7df 789 return result;
AndyA 0:bddb8cd5e7df 790 }
AndyA 0:bddb8cd5e7df 791
AndyA 0:bddb8cd5e7df 792 uint32_t DW1000::readRegister32(uint8_t reg, uint16_t subaddress)
AndyA 0:bddb8cd5e7df 793 {
AndyA 0:bddb8cd5e7df 794 uint32_t result;
AndyA 0:bddb8cd5e7df 795 readRegister(reg, subaddress, (uint8_t*)&result, 4);
AndyA 0:bddb8cd5e7df 796 return result;
AndyA 0:bddb8cd5e7df 797 }
AndyA 0:bddb8cd5e7df 798
AndyA 0:bddb8cd5e7df 799
AndyA 0:bddb8cd5e7df 800 uint64_t DW1000::readRegister40(uint8_t reg, uint16_t subaddress)
AndyA 0:bddb8cd5e7df 801 {
AndyA 0:bddb8cd5e7df 802 uint64_t result = 0;
AndyA 0:bddb8cd5e7df 803 readRegister(reg, subaddress, (uint8_t*)&result, 5);
AndyA 0:bddb8cd5e7df 804 return result;
AndyA 0:bddb8cd5e7df 805 }
AndyA 0:bddb8cd5e7df 806 uint64_t DW1000::readRegister64(uint8_t reg, uint16_t subaddress)
AndyA 0:bddb8cd5e7df 807 {
AndyA 0:bddb8cd5e7df 808 uint64_t result;
AndyA 0:bddb8cd5e7df 809 readRegister(reg, subaddress, (uint8_t*)&result, 8);
AndyA 0:bddb8cd5e7df 810 return result;
AndyA 0:bddb8cd5e7df 811 }
AndyA 0:bddb8cd5e7df 812
AndyA 0:bddb8cd5e7df 813 void DW1000::writeRegister8(uint8_t reg, uint16_t subaddress, uint8_t buffer)
AndyA 0:bddb8cd5e7df 814 {
AndyA 0:bddb8cd5e7df 815 writeRegister(reg, subaddress, &buffer, 1);
AndyA 0:bddb8cd5e7df 816 }
AndyA 0:bddb8cd5e7df 817
AndyA 0:bddb8cd5e7df 818 void DW1000::writeRegister16(uint8_t reg, uint16_t subaddress, uint16_t buffer)
AndyA 0:bddb8cd5e7df 819 {
AndyA 0:bddb8cd5e7df 820 writeRegister(reg, subaddress, (uint8_t*)&buffer, 2);
AndyA 0:bddb8cd5e7df 821 }
AndyA 0:bddb8cd5e7df 822
AndyA 0:bddb8cd5e7df 823 void DW1000::writeRegister32(uint8_t reg, uint16_t subaddress, uint32_t buffer)
AndyA 0:bddb8cd5e7df 824 {
AndyA 0:bddb8cd5e7df 825 writeRegister(reg, subaddress, (uint8_t*)&buffer, 4);
AndyA 0:bddb8cd5e7df 826 }
AndyA 0:bddb8cd5e7df 827
AndyA 0:bddb8cd5e7df 828 void DW1000::writeRegister40(uint8_t reg, uint16_t subaddress, uint64_t buffer)
AndyA 0:bddb8cd5e7df 829 {
AndyA 0:bddb8cd5e7df 830 writeRegister(reg, subaddress, (uint8_t*)&buffer, 5);
AndyA 0:bddb8cd5e7df 831 }
AndyA 0:bddb8cd5e7df 832
AndyA 0:bddb8cd5e7df 833 void DW1000::readRegister(uint8_t reg, uint16_t subaddress, uint8_t *buffer, int length)
AndyA 0:bddb8cd5e7df 834 {
AndyA 0:bddb8cd5e7df 835 setupTransaction(reg, subaddress, false);
AndyA 0:bddb8cd5e7df 836 for(int i=0; i<length; i++) // get data
AndyA 0:bddb8cd5e7df 837 buffer[i] = spi.write(0x00);
AndyA 0:bddb8cd5e7df 838 deselect();
AndyA 0:bddb8cd5e7df 839 }
AndyA 0:bddb8cd5e7df 840
AndyA 0:bddb8cd5e7df 841 void DW1000::writeRegister(uint8_t reg, uint16_t subaddress, uint8_t *buffer, int length)
AndyA 0:bddb8cd5e7df 842 {
AndyA 0:bddb8cd5e7df 843 setupTransaction(reg, subaddress, true);
AndyA 0:bddb8cd5e7df 844 for(int i=0; i<length; i++) // put data
AndyA 0:bddb8cd5e7df 845 spi.write(buffer[i]);
AndyA 0:bddb8cd5e7df 846 deselect();
AndyA 0:bddb8cd5e7df 847 }
AndyA 0:bddb8cd5e7df 848
AndyA 0:bddb8cd5e7df 849 void DW1000::setupTransaction(uint8_t reg, uint16_t subaddress, bool write)
AndyA 0:bddb8cd5e7df 850 {
AndyA 0:bddb8cd5e7df 851 reg |= (write * DW1000_WRITE_FLAG); // set read/write flag
AndyA 0:bddb8cd5e7df 852 select();
AndyA 0:bddb8cd5e7df 853 if (subaddress > 0) { // there's a subadress, we need to set flag and send second header byte
AndyA 0:bddb8cd5e7df 854 spi.write(reg | DW1000_SUBADDRESS_FLAG);
AndyA 0:bddb8cd5e7df 855 if (subaddress > 0x7F) { // sub address too long, we need to set flag and send third header byte
AndyA 0:bddb8cd5e7df 856 spi.write((uint8_t)(subaddress & 0x7F) | DW1000_2_SUBADDRESS_FLAG); // and
AndyA 0:bddb8cd5e7df 857 spi.write((uint8_t)(subaddress >> 7));
AndyA 0:bddb8cd5e7df 858 } else {
AndyA 0:bddb8cd5e7df 859 spi.write((uint8_t)subaddress);
AndyA 0:bddb8cd5e7df 860 }
AndyA 0:bddb8cd5e7df 861 } else {
AndyA 0:bddb8cd5e7df 862 spi.write(reg); // say which register address we want to access
AndyA 0:bddb8cd5e7df 863 }
AndyA 0:bddb8cd5e7df 864 }
AndyA 0:bddb8cd5e7df 865
AndyA 0:bddb8cd5e7df 866 void DW1000::select() // always called to start an SPI transmission
AndyA 0:bddb8cd5e7df 867 {
AndyA 0:bddb8cd5e7df 868 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 869 cs = 0; // set Cable Select pin low to start transmission
AndyA 0:bddb8cd5e7df 870 }
AndyA 0:bddb8cd5e7df 871
AndyA 0:bddb8cd5e7df 872 void DW1000::deselect() // always called to end an SPI transmission
AndyA 0:bddb8cd5e7df 873 {
AndyA 0:bddb8cd5e7df 874 cs = 1; // set Cable Select pin high to stop transmission
AndyA 0:bddb8cd5e7df 875 irq.enable_irq(); // reenable the interrupt handler
AndyA 0:bddb8cd5e7df 876 }