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

Dependencies:   BurstSPI

Revision:
5:68ffaa5962d1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DW1000.cpp.orig	Thu Apr 07 16:27:51 2016 +0000
@@ -0,0 +1,983 @@
+#include "DW1000.h"
+
+#define SPIRATE_PLL (5*1000*1000)
+#define SPIRATE_OSC (2*1000*1000)
+
+DW1000::DW1000(UWBMode setup, PinName MOSI, PinName MISO, PinName SCLK, PinName CS, PinName IRQ) : irq(IRQ), spi(MOSI, MISO, SCLK), cs(CS)
+{
+    setCallbacks(NULL, NULL);
+
+    deselect();                         // Chip must be deselected first
+    spi.format(8,0);                    // Setup the spi for standard 8 bit data and SPI-Mode 0 (GPIO5, GPIO6 open circuit or ground on DW1000)
+    spi.frequency(SPIRATE_PLL);             // with a 1MHz clock rate (worked up to 49MHz in our Test)
+
+    resetAll();                         // we do a soft reset of the DW1000 everytime the driver starts
+
+    switch (setup) {
+        case user110k:  // values from Matthias Grob & Manuel Stalder - ETH Zürich - library
+
+            systemConfig.setChannel(5);
+            systemConfig.setPRF(DW1000Setup::prf16MHz);
+            systemConfig.setDataRate(DW1000Setup::kbps110);
+            systemConfig.setSfd(DW1000Setup::standard);
+            systemConfig.setPreambleLength(DW1000Setup::pre1024);
+            systemConfig.setPreambleCode(3);
+            systemConfig.setSmartPower(false);
+
+            setupRadio();
+
+            setTxPower(230); // power = 23dB gain
+
+            setRxDelay(1<<14); // set delays to 2^14 (1/4 of max)
+            setTxDelay(1<<14);
+            break;
+
+        case tunedDefault:    // User Manual "2.5.5 Default Configurations that should be modified" p. 22
+        default:
+
+            systemConfig.setChannel(5);
+            systemConfig.setPRF(DW1000Setup::prf16MHz);
+            systemConfig.setDataRate(DW1000Setup::kbps6800);
+            systemConfig.setSfd(DW1000Setup::standard);
+            systemConfig.setPreambleLength(DW1000Setup::pre128);
+            systemConfig.setPreambleCode(3);
+            systemConfig.setSmartPower(false);
+
+            setupRadio();
+
+            setTxPower(230,260,290); // power = 23dB gain
+            setRxDelay(0);
+            setTxDelay(0);
+
+            break;
+        case minPacketSize:
+            systemConfig.setChannel(5);
+            systemConfig.setPRF(DW1000Setup::prf64MHz);
+            systemConfig.setDataRate(DW1000Setup::kbps6800);
+            systemConfig.setSfd(DW1000Setup::standard);
+            systemConfig.setPreambleLength(DW1000Setup::pre64);
+            systemConfig.setPreambleCode(10);
+            systemConfig.setSmartPower(true);
+
+            setupRadio();
+            uint16_t txPower = 25*10; // 25dB gain.
+            // 2 packets per ms max. So can increase TX power of 250us packets by 10log(4/2) dB and 125us packets by 10log(8/2) dB
+            setTxPower(txPower,txPower,txPower+30,txPower+60); // power = 23dB gain
+
+            setRxDelay(0);
+            setTxDelay(0);
+
+            break;
+    }
+
+
+    irq.rise(this, &DW1000::ISR);       // attach interrupt handler to rising edge of interrupt pin from DW1000
+}
+
+void DW1000::getSetup(char *buffer, int len)
+{
+
+    char dataRateString[10];
+    if (systemConfig.getDataRate() == DW1000Setup::kbps6800)
+        strcpy(dataRateString,"6.8 Mbps");
+    else if (systemConfig.getDataRate() == DW1000Setup::kbps850)
+        strcpy(dataRateString,"850 kbps");
+    else
+        strcpy(dataRateString,"110 kbps");
+
+    char preambleString[8];
+    switch (systemConfig.getPreambleLength()) {
+        default:
+            strcpy(preambleString,"error");
+            break;
+        case DW1000Setup::pre64:
+            strcpy(preambleString,"64");
+            break;
+        case DW1000Setup::pre128:
+            strcpy(preambleString,"128");
+            break;
+        case DW1000Setup::pre256:
+            strcpy(preambleString,"256");
+            break;
+        case DW1000Setup::pre512:
+            strcpy(preambleString,"512");
+            break;
+        case DW1000Setup::pre1024:
+            strcpy(preambleString,"1024");
+            break;
+        case DW1000Setup::pre1536:
+            strcpy(preambleString,"1536");
+            break;
+        case DW1000Setup::pre2048:
+            strcpy(preambleString,"2048");
+            break;
+        case DW1000Setup::pre4096:
+            strcpy(preambleString,"4096");
+            break;
+    }
+
+    snprintf(buffer,len,"Channel:\t%u\r\nPRF:\t%s\r\nData Rate:\t%s\r\nPreamble length:\t%s\r\nPreamble code:\t%u\r\nSmart power:\t%s\r\nSFD:\t%s\r\n",
+             systemConfig.getChannel(),
+             (systemConfig.getPRF() == DW1000Setup::prf16MHz)?"16 MHz":"64 MHz",
+             dataRateString,
+             preambleString,
+             systemConfig.getPreambleCode(),
+             systemConfig.getSmartPower()?"Enabled":"Disabled",
+             (systemConfig.getSfd() == DW1000Setup::standard)?"Standard":"Non-standard");
+
+}
+
+
+void DW1000::setupRadio()
+{
+    setupAGC();
+    setupRxConfig();
+    setupLDE();
+    setupChannel();
+    setupAnalogRF();
+    setupFreqSynth();
+    setupTxCalibration();
+    setupTxFrameCtrl();
+    setupSystemConfig();
+
+}
+
+void DW1000::setupAGC()
+{
+
+    writeRegister16(DW1000_AGC_CTRL, DWAGCCTRL_AGC_CTRL1, 0x0001);
+    if (systemConfig.getPRF() == DW1000Setup::prf16MHz)
+        writeRegister16(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE1, 0x8870);
+    else
+        writeRegister16(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE1, 0x889B);
+
+    writeRegister32(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE2, 0x2502A907);
+    writeRegister16(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE3, 0x0035);
+}
+
+void DW1000::setupSystemConfig()
+{
+    uint32_t valueToUse = 0;
+    valueToUse |= 1<<9; // IRQ output is active high (default)
+    valueToUse |= 1<<12; // Disable double buffered Rx (default)
+
+//    valueToUse |= 3<<16; // enable long (>125bytes data) packets
+
+    if (!systemConfig.getSmartPower())
+        valueToUse |= 1<<18; // disable smart power
+
+    if (systemConfig.getDataRate() == DW1000Setup::kbps110)
+        valueToUse |= 1<<22;
+
+    valueToUse |= 1<<29;// enable auto reenabling receiver after error
+
+    writeRegister32(DW1000_SYS_CFG, 0, valueToUse);
+}
+
+void DW1000::setupRxConfig()
+{
+
+    switch (systemConfig.getDataRate()) {
+        case DW1000Setup::kbps110:
+            if (systemConfig.getSfd() == DW1000Setup::standard)
+                writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE0B, 0x000A);
+            else
+                writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE0B, 0x0016);
+            break;
+        case DW1000Setup::kbps850:
+            if (systemConfig.getSfd() == DW1000Setup::standard)
+                writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE0B, 0x0001);
+            else
+                writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE0B, 0x0006);
+            break;
+        case DW1000Setup::kbps6800:
+        default:
+            if (systemConfig.getSfd() == DW1000Setup::standard)
+                writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE0B, 0x0001);
+            else
+                writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE0B, 0x0002);
+            break;
+    }
+
+    if (systemConfig.getPRF() == DW1000Setup::prf16MHz)
+        writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE1A, 0x0087);             //DRX_TUNE1a for 16MHz PRF
+    else
+        writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE1A, 0x008D);
+
+    switch (systemConfig.getPreambleLength()) {
+        case DW1000Setup::pre1536:
+        case DW1000Setup::pre2048:
+        case DW1000Setup::pre4096:
+            writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE1B, 0x0064);             //DRX_TUNE1b for 110kbps & > 1024 symbols
+            break;
+        default: // 128 to 1024
+            writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE1B, 0x0020);             //DRX_TUNE1b for 128- 1024 symbols
+            break;
+        case DW1000Setup::pre64:
+            writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE1B, 0x0010);             //DRX_TUNE1b for 64 symbols
+            break;
+    }
+
+    switch (systemConfig.getPreambleLength()) {
+        case DW1000Setup::pre64:
+        case DW1000Setup::pre128:  // PAC = 8
+            if (systemConfig.getPRF() == DW1000Setup::prf16MHz)
+                writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x311A002D);             //DRX_TUNE2 PAC 8 for 64MHz PRF
+            else
+                writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x313B006B);        //DRX_TUNE2 PAC 8 for 64MHz PRF
+            break;
+        case DW1000Setup::pre256:
+        case DW1000Setup::pre512: // PAC = 16
+            if (systemConfig.getPRF() == DW1000Setup::prf16MHz)
+                writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x331A0052);             //DRX_TUNE2 PAC 16 for 64MHz PRF
+            else
+                writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x333B00BE);        //DRX_TUNE2 PAC 16 for 64MHz PRF
+            break;
+        case DW1000Setup::pre1024: // PAC = 32
+            if (systemConfig.getPRF() == DW1000Setup::prf16MHz)
+                writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x351A009A);             //DRX_TUNE2 PAC 32 for 64MHz PRF
+            else
+                writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x353B015E);        //DRX_TUNE2 PAC 32 for 64MHz PRF
+            break;
+        case DW1000Setup::pre1536:
+        case DW1000Setup::pre2048:
+        case DW1000Setup::pre4096: // PAC = 64
+            if (systemConfig.getPRF() == DW1000Setup::prf16MHz)
+                writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x371A011D);             //DRX_TUNE2 PAC 64 for 64MHz PRF
+            else
+                writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x373B0296);        //DRX_TUNE2 PAC 64 for 64MHz PRF
+            break;
+    }
+
+
+    if (systemConfig.getPreambleLength() == DW1000Setup::pre64)
+        writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE4H, 0x0010);
+    else
+        writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE4H, 0x0028);
+
+}
+
+
+void DW1000::setupLDE()
+{
+
+    writeRegister8 (DW1000_LDE_CTRL, DWLDE_LDE_CFG1, 0x13 | 0x03<<5);  //NTM = 13 (12 may be better in some situations. PMULT = 3
+
+    if (systemConfig.getPRF() == DW1000Setup::prf16MHz)
+        writeRegister16(DW1000_LDE_CTRL, DWLDE_LDE_CFG2, 0x1607);           //LDE_CFG2 for 16MHz PRF
+    else
+        writeRegister16(DW1000_LDE_CTRL, DWLDE_LDE_CFG2, 0x0607);           //LDE_CFG2 for 64MHz PRF
+
+    uint16_t replicaCoeff;
+    switch (systemConfig.getPreambleCode()) {
+        default:
+        case 1:
+        case 2:
+            replicaCoeff = 0x5998;
+            break;
+        case 3:
+            replicaCoeff = 0x51EA;
+            break;
+        case 4:
+            replicaCoeff = 0x428E;
+            break;
+        case 5:
+            replicaCoeff = 0x451E;
+            break;
+        case 6:
+            replicaCoeff = 0x2E14;
+            break;
+        case 7:
+            replicaCoeff = 0x8000;
+            break;
+        case 8:
+            replicaCoeff = 0x51EA;
+            break;
+        case 9:
+            replicaCoeff = 0x28F4;
+            break;
+        case 10:
+            replicaCoeff = 0x3332;
+            break;
+        case 11:
+            replicaCoeff = 0x3AE0;
+            break;
+        case 12:
+            replicaCoeff = 0x3D70;
+            break;
+        case 13:
+            replicaCoeff = 0x3AE0;
+            break;
+        case 14:
+            replicaCoeff = 0x35C2;
+            break;
+        case 15:
+            replicaCoeff = 0x2B84;
+            break;
+        case 16:
+            replicaCoeff = 0x35C2;
+            break;
+        case 17:
+            replicaCoeff = 0x3332;
+            break;
+        case 18:
+            replicaCoeff = 0x35C2;
+            break;
+        case 19:
+            replicaCoeff = 0x35C2;
+            break;
+        case 20:
+            replicaCoeff = 0x47AE;
+            break;
+        case 21:
+            replicaCoeff = 0x3AE0;
+            break;
+        case 22:
+            replicaCoeff = 0x3850;
+            break;
+        case 23:
+            replicaCoeff = 0x30A2;
+            break;
+        case 24:
+            replicaCoeff = 0x3850;
+            break;
+    }
+
+    if (systemConfig.getDataRate() == DW1000Setup::kbps110)
+        replicaCoeff = replicaCoeff>>3;
+
+    writeRegister16(DW1000_LDE_CTRL, DWLDE_LDE_REPC, replicaCoeff);
+
+    loadLDE();
+}
+
+void DW1000::setupChannel()
+{
+    uint32_t registerValue = 0;
+
+    registerValue = systemConfig.getChannel(); // set Tx channel
+    registerValue |= systemConfig.getChannel()<<4; // set Rx channel
+
+    if (systemConfig.getPRF() == DW1000Setup::prf16MHz) // set PRF (2 bit value 01 or 10)
+        registerValue |= 0x01 << 18;
+    else
+        registerValue |= 0x02 << 18;
+
+    if (systemConfig.getSfd() == DW1000Setup::decaWave) 
+        registerValue |= 0x01 << 17; // enable DW own SFD
+
+    if (systemConfig.getSfd() == DW1000Setup::user) {     
+        registerValue |= 0x01 << 20; // enable user set SFD Tx
+        registerValue |= 0x01 << 21; // enable user set SFD Rx
+    }
+
+    registerValue |= systemConfig.getPreambleCode() << 22; // set Tx preamble code
+    registerValue |= systemConfig.getPreambleCode() << 27; // set Rx preamble code
+
+    writeRegister32(DW1000_CHAN_CTRL, 0, registerValue);
+}
+
+
+uint8_t DW1000::powerToRegValue(uint16_t powercB)
+{
+
+    // course power control - 0 = 18dB, 6 = 0dB in 3dB steps.
+    uint8_t course = powercB / 30;
+
+    if(course > 6)
+        course = 6;
+
+    // remaining power
+    powercB -= course * 30;
+
+    // value in reg is inverse.
+    course = 6-course;
+
+    // fine control in steps of 0.5dB
+    uint8_t fine =  powercB / 5;
+    if (fine > 31)
+        fine = 31;
+
+
+    return (course << 5) | fine;
+
+}
+
+// transmit power: 0 to 33.5 dB gain in steps of 0.5. Inputs are in 10ths of a dB (0 to 335)
+void DW1000::setTxPower(uint16_t normalPowercB, uint16_t boost500, uint16_t boost250, uint16_t boost125)
+{
+
+    if(normalPowercB > 335)
+        normalPowercB = 335;
+
+    if (boost500 < normalPowercB)
+        boost500 = normalPowercB;
+    if(boost500 > 335)
+        boost500 = 335;
+
+    if (boost250 < boost500)
+        boost250 = boost500;
+    if(boost250 > 335)
+        boost250 = 335;
+
+    if (boost125 < boost250)
+        boost125 = boost250;
+    if(boost125 > 335)
+        boost125 = 335;
+
+    if (systemConfig.getSmartPower() == false) {
+        boost500 = normalPowercB;
+        boost250 = normalPowercB;
+        boost125 = normalPowercB;
+    }
+
+    uint32_t powerReg = powerToRegValue(normalPowercB);
+    powerReg |= powerToRegValue(boost500) << 8;
+    powerReg |= powerToRegValue(boost250) << 16;
+    powerReg |= powerToRegValue(boost125) << 24;
+}
+
+void DW1000::setupAnalogRF()
+{
+    switch (systemConfig.getChannel()) {
+        case 1:
+            writeRegister32(DW1000_RF_CONF, DWRFCONF_RF_TXCTRL, 0x00005C40);
+            break;
+        case 2:
+            writeRegister32(DW1000_RF_CONF, DWRFCONF_RF_TXCTRL, 0x00045CA0);
+            break;
+        case 3:
+            writeRegister32(DW1000_RF_CONF, DWRFCONF_RF_TXCTRL, 0x00086CC0);
+            break;
+        case 4:
+            writeRegister32(DW1000_RF_CONF, DWRFCONF_RF_TXCTRL, 0x00045C80);
+            break;
+        case 5:
+        default:
+            writeRegister32(DW1000_RF_CONF, DWRFCONF_RF_TXCTRL, 0x001E3FE0);
+            break;
+        case 7:
+            writeRegister32(DW1000_RF_CONF, DWRFCONF_RF_TXCTRL, 0x001E7DE0);
+            break;
+    }
+
+    switch (systemConfig.getChannel()) {
+        case 1:
+        case 2:
+        case 3:
+        case 5:
+        default:
+            writeRegister8(DW1000_RF_CONF, DWRFCONF_RF_RXCTRLH, 0xD8);
+            break;
+        case 4:
+        case 7:
+            writeRegister8(DW1000_RF_CONF, DWRFCONF_RF_RXCTRLH, 0xBC);
+            break;
+    }
+
+    loadLDOTUNE();
+
+}
+
+void DW1000::setupTxCalibration()
+{
+    switch (systemConfig.getChannel()) {
+        case 1:
+            writeRegister8 (DW1000_TX_CAL, DWTXCAL_TC_PGDELAY, 0xC9);
+            break;
+        case 2:
+            writeRegister8 (DW1000_TX_CAL, DWTXCAL_TC_PGDELAY, 0xC2);
+            break;
+        case 3:
+            writeRegister8 (DW1000_TX_CAL, DWTXCAL_TC_PGDELAY, 0xC5);
+            break;
+        case 4:
+            writeRegister8 (DW1000_TX_CAL, DWTXCAL_TC_PGDELAY, 0x95);
+            break;
+        case 5:
+        default:
+            writeRegister8 (DW1000_TX_CAL, DWTXCAL_TC_PGDELAY, 0xC0);
+            break;
+        case 7:
+            writeRegister8 (DW1000_TX_CAL, DWTXCAL_TC_PGDELAY, 0x93);
+            break;
+    }
+}
+
+void DW1000::setupFreqSynth()
+{
+
+    switch (systemConfig.getChannel()) {
+        case 1:
+            writeRegister32 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLCFG, 0x09000407);         //FS_PLLCFG for channel 1
+            writeRegister8 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLTUNE, 0x1E);
+            break;
+        case 2:
+        case 4:
+            writeRegister32 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLCFG, 0x08400508);         //FS_PLLCFG for channel 2,4
+            writeRegister8 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLTUNE, 0x26);
+            break;
+        case 3:
+            writeRegister32 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLCFG, 0x08401009);         //FS_PLLCFG for channel 3
+            writeRegister8 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLTUNE, 0x5E);
+            break;
+        case 5:
+        case 7:
+        default:
+            writeRegister32 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLCFG, 0x0800041D);         //FS_PLLCFG for channel 5,7
+            writeRegister8 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLTUNE, 0xBE);                //FS_PLLTUNE for channel 5
+            break;
+    }
+}
+
+void DW1000::setupTxFrameCtrl()
+{
+    uint32_t frameCtrlValue = 0;
+    switch (systemConfig.getDataRate()) {
+        case DW1000Setup::kbps110:
+            break;
+        case DW1000Setup::kbps850:
+            frameCtrlValue |= 0x01<<13;
+            break;
+        case DW1000Setup::kbps6800:
+        default:
+            frameCtrlValue |= 0x02<<13;
+            break;
+    }
+    frameCtrlValue |= 0x01<<15;
+
+    if (systemConfig.getPRF() == DW1000Setup::prf16MHz)
+        frameCtrlValue |= 0x01<<16;
+    else
+        frameCtrlValue |= 0x02<<16;
+
+    switch    (systemConfig.getPreambleLength())            {
+        case DW1000Setup::pre64:
+            frameCtrlValue |= 0x01<<18; // TXPSR
+            frameCtrlValue |= 0x00<<20; // PE
+            break;
+        case DW1000Setup::pre128:
+        default:
+            frameCtrlValue |= 0x01<<18; // TXPSR
+            frameCtrlValue |= 0x01<<20; // PE
+            break;
+        case DW1000Setup::pre256:
+            frameCtrlValue |= 0x01<<18; // TXPSR
+            frameCtrlValue |= 0x02<<20; // PE
+            break;
+        case DW1000Setup::pre512:
+            frameCtrlValue |= 0x01<<18; // TXPSR
+            frameCtrlValue |= 0x03<<20; // PE
+            break;
+        case DW1000Setup::pre1024:
+            frameCtrlValue |= 0x02<<18; // TXPSR
+            frameCtrlValue |= 0x00<<20; // PE
+            break;
+        case DW1000Setup::pre1536:
+            frameCtrlValue |= 0x02<<18; // TXPSR
+            frameCtrlValue |= 0x01<<20; // PE
+            break;
+        case DW1000Setup::pre2048:
+            frameCtrlValue |= 0x02<<18; // TXPSR
+            frameCtrlValue |= 0x02<<20; // PE
+            break;
+        case DW1000Setup::pre4096:
+            frameCtrlValue |= 0x03<<18; // TXPSR
+            frameCtrlValue |= 0x00<<20; // PE
+            break;
+    }
+    writeRegister32(DW1000_TX_FCTRL,0,frameCtrlValue);
+}
+
+void DW1000::setRxDelay(uint16_t ticks)
+{
+    writeRegister16(DW1000_LDE_CTRL, DWLDE_LDE_RXANTD, ticks);
+}
+void DW1000::setTxDelay(uint16_t ticks)
+{
+    writeRegister16(DW1000_TX_ANTD, 0, ticks);
+}
+
+void DW1000::setCallbacks(void (*callbackRX)(void), void (*callbackTX)(void))
+{
+    bool RX = false;
+    bool TX = false;
+    if (callbackRX) {
+        DW1000::callbackRX.attach(callbackRX);
+        RX = true;
+    }
+    if (callbackTX) {
+        DW1000::callbackTX.attach(callbackTX);
+        TX = true;
+    }
+    setInterrupt(RX,TX);
+}
+
+uint32_t DW1000::getDeviceID()
+{
+    uint32_t result;
+    readRegister(DW1000_DEV_ID, 0, (uint8_t*)&result, 4);
+    return result;
+}
+
+uint64_t DW1000::getEUI()
+{
+    uint64_t result;
+    readRegister(DW1000_EUI, 0, (uint8_t*)&result, 8);
+    return result;
+}
+
+void DW1000::setEUI(uint64_t EUI)
+{
+    writeRegister(DW1000_EUI, 0, (uint8_t*)&EUI, 8);
+}
+
+
+float DW1000::getVoltage()
+{
+    uint8_t data;
+
+    writeRegister8(DW1000_RF_CONF, 0x11, 0x80);
+    writeRegister8(DW1000_RF_CONF, 0x12, 0x0A);
+    writeRegister8(DW1000_RF_CONF, 0x12, 0x0F);
+    writeRegister8(DW1000_TX_CAL, 0x00, 0x01);
+    writeRegister8(DW1000_TX_CAL, 0x00, 0x00);
+    data = readRegister8(DW1000_TX_CAL, 0x03);               // get the 8-Bit reading for Voltage
+    float Voltage = (float)(data - (readOTP(0x08)&0x00ff)) *0.00578 + 3.3;
+    return Voltage;
+}
+
+float DW1000::getTemperature()
+{
+    uint8_t data;
+
+    writeRegister8(DW1000_RF_CONF, 0x11, 0x80);
+    writeRegister8(DW1000_RF_CONF, 0x12, 0x0A);
+    writeRegister8(DW1000_RF_CONF, 0x12, 0x0F);
+    writeRegister8(DW1000_TX_CAL, 0x00, 0x01);
+    writeRegister8(DW1000_TX_CAL, 0x00, 0x00);
+    data = readRegister16(DW1000_TX_CAL, 0x04);               // get the 8-Bit reading for Temperature
+    float temperature =  (float)(data - (readOTP(0x09) & 0x00ff))*0.9 + 23;
+    return temperature;
+}
+
+
+uint64_t DW1000::getStatus()
+{
+    return readRegister40(DW1000_SYS_STATUS, 0);
+}
+
+uint64_t DW1000::getRXTimestamp()
+{
+    return readRegister40(DW1000_RX_TIME, 0);
+}
+
+uint64_t DW1000::getTXTimestamp()
+{
+    return readRegister40(DW1000_TX_TIME, 0);
+}
+
+void DW1000::sendString(char* message)
+{
+    sendFrame((uint8_t*)message, strlen(message)+1);
+}
+
+void DW1000::receiveString(char* message)
+{
+    readRegister(DW1000_RX_BUFFER, 0, (uint8_t*)message, getFramelength());  // get data from buffer
+}
+
+void DW1000::sendFrame(uint8_t* message, uint16_t length)
+{
+    //if (length >= 1021) length = 1021;                            // check for maximim length a frame can have with 1024 Byte frames [not used, see constructor]
+    if (length >= 125) length = 125;                                // check for maximim length a frame can have with 127 Byte frames
+    uint8_t len_7bit = length;
+    writeRegister(DW1000_TX_BUFFER, 0, message, len_7bit);            // fill buffer
+
+    /* support for frames over 127 bytes
+        uint8_t backup = readRegister8(DW1000_TX_FCTRL, 1);             // put length of frame
+        length += 2;                                                    // including 2 CRC Bytes
+        length = ((backup & 0xFC) << 8) | (length & 0x03FF);
+        writeRegister16(DW1000_TX_FCTRL, 0, length);
+    */
+    len_7bit += 2;                                                    // including 2 CRC Bytes
+    writeRegister8(DW1000_TX_FCTRL, 0, len_7bit);
+
+    stopTRX();                                                      // stop receiving
+    writeRegister8(DW1000_SYS_CTRL, 0, 0x02 | 0x80);                       // trigger sending process by setting the TXSTRT bit
+//    startRX();                                                      // enable receiver again
+}
+
+void DW1000::setupSyncedFrame(uint8_t* message, uint16_t length)
+{
+    //if (length >= 1021) length = 1021;                            // check for maximim length a frame can have with 1024 Byte frames [not used, see constructor]
+    if (length >= 125) length = 125;                                // check for maximim length a frame can have with 127 Byte frames
+    writeRegister(DW1000_TX_BUFFER, 0, message, length);            // fill buffer
+
+    uint8_t backup = readRegister8(DW1000_TX_FCTRL, 1);             // put length of frame
+    length += 2;                                                    // including 2 CRC Bytes
+    length = ((backup & 0xFC) << 8) | (length & 0x03FF);
+    writeRegister16(DW1000_TX_FCTRL, 0, length);
+}
+
+void DW1000::armSyncedFrame()
+{
+    stopTRX();                                                      // stop receiving
+    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)
+}
+
+void DW1000::sendDelayedFrame(uint8_t* message, uint16_t length, uint64_t TxTimestamp)
+{
+    //if (length >= 1021) length = 1021;                            // check for maximim length a frame can have with 1024 Byte frames [not used, see constructor]
+    if (length >= 125) length = 125;                                // check for maximim length a frame can have with 127 Byte frames
+    writeRegister(DW1000_TX_BUFFER, 0, message, length);            // fill buffer
+
+    uint8_t backup = readRegister8(DW1000_TX_FCTRL, 1);             // put length of frame
+    length += 2;                                                    // including 2 CRC Bytes
+    length = ((backup & 0xFC) << 8) | (length & 0x03FF);
+    writeRegister16(DW1000_TX_FCTRL, 0, length);
+
+    writeRegister40(DW1000_DX_TIME, 0, TxTimestamp);                //write the timestamp on which to send the message
+
+    stopTRX();                                                      // stop receiving
+    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.
+}
+
+void DW1000::startRX()
+{
+    writeRegister8(DW1000_SYS_CTRL, 0x01, 0x01);                    // start listening for preamble by setting the RXENAB bit
+}
+
+void DW1000::stopTRX()
+{
+    writeRegister8(DW1000_SYS_CTRL, 0, 0x40);                       // disable tranceiver go back to idle mode
+}
+
+// PRIVATE Methods ------------------------------------------------------------------------------------
+void DW1000::loadLDE()                                              // initialise LDE algorithm LDELOAD User Manual p22
+{
+    spi.frequency(SPIRATE_OSC);             // with a 1MHz clock rate (worked up to 49MHz in our Test)
+
+    writeRegister16(DW1000_PMSC, 0, 0x0301);                        // set clock to XTAL so OTP is reliable
+    writeRegister16(DW1000_OTP_IF, DWOTP_OTP_CTRL, 0x8000);                   // set LDELOAD bit in OTP
+    wait_us(150);
+    writeRegister16(DW1000_PMSC, 0, 0x0200);                        // recover to PLL clock
+
+    wait_ms(1);
+
+    spi.frequency(SPIRATE_PLL);             // with a 1MHz clock rate (worked up to 49MHz in our Test)
+
+}
+
+void DW1000::loadLDOTUNE()
+{
+    uint64_t LDOTuningValue = readOTP(0x0004);
+    if (LDOTuningValue != 0) {
+        LDOTuningValue = LDOTuningValue | ((uint64_t)(readOTP(0x0005) & 0x00ff) << 32);
+        writeRegister40(DW1000_RF_CONF,DWRFCONF_RF_LDOTUNE,LDOTuningValue);
+    }
+}
+
+void DW1000::resetRX()
+{
+    writeRegister8(DW1000_PMSC, 3, 0xE0);   // set RX reset
+    writeRegister8(DW1000_PMSC, 3, 0xF0);   // clear RX reset
+}
+
+void DW1000::resetAll()
+{
+    spi.frequency(SPIRATE_OSC);             // with a 1MHz clock rate (worked up to 49MHz in our Test)
+
+    writeRegister8(DW1000_PMSC, 0, 0x01);   // set clock to XTAL
+    writeRegister8(DW1000_PMSC, 3, 0x00);   // set All reset
+    wait_us(10);                            // wait for PLL to lock
+    writeRegister8(DW1000_PMSC, 3, 0xF0);   // clear All reset
+
+    wait_ms(1);
+
+    spi.frequency(SPIRATE_PLL);             // with a 1MHz clock rate (worked up to 49MHz in our Test)
+}
+
+/// After writes have been completed reset the device.
+bool DW1000::writeOTP(uint16_t word_address,uint32_t data)
+{
+    spi.frequency(SPIRATE_OSC);             // with a 1MHz clock rate (worked up to 49MHz in our Test)
+
+    writeRegister8(DW1000_PMSC, 0, 0x01);   // set clock to XTAL
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x03);  //
+    writeRegister16(DW1000_OTP_IF,DWOTP_OTP_WDAT,0x9220);  //
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x08);  //
+    wait_ms(1);
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x02);  //
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x88);  //
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x80);  //
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00);  //
+
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x05);  //
+    writeRegister16(DW1000_OTP_IF,DWOTP_OTP_WDAT,0x000E);  //
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x08);  //
+    wait_ms(1);
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x04);  //
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x88);  //
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x80);  //
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00);  //
+
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x01);  //
+    writeRegister16(DW1000_OTP_IF,DWOTP_OTP_WDAT,0x1024);  //
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x08);  //
+    wait_ms(1);
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL+1,0x00);  //
+
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00);  //
+    writeRegister32(DW1000_OTP_IF,DWOTP_OTP_WDAT,data);  //
+    writeRegister16(DW1000_OTP_IF,DWOTP_OTP_ADDR,word_address);  //
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x40);  //
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00);  //
+    wait_ms(1);
+
+    for (int i=0; i<10; i++) {
+        if (readOTP(word_address) == data)
+            return true;
+        writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x40);  // retry
+        writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00);
+        wait_ms(1);
+    }
+    return false;
+}
+
+
+uint32_t DW1000::readOTP(uint16_t word_address)
+{
+    writeRegister16(DW1000_OTP_IF,DWOTP_OTP_ADDR,word_address); // write address
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x03);  // read address load
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x01);  // read
+    uint32_t data = readRegister32(DW1000_OTP_IF,DWOTP_OTP_RDAT);
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x00);  // OTP idle
+    return data;
+}
+
+void DW1000::setInterrupt(bool RX, bool TX)
+{
+    writeRegister16(DW1000_SYS_MASK, 0, RX*0x4000 | TX*0x0080);  // RX good frame 0x4000, TX done 0x0080
+}
+
+void DW1000::ISR()
+{
+    uint64_t status = getStatus();
+    if (status & 0x4000) {                                          // a frame was received
+        callbackRX.call();
+        writeRegister16(DW1000_SYS_STATUS, 0, 0x6F00);              // clearing of receiving status bits
+    }
+    if (status & 0x80) {                                            // sending complete
+        callbackTX.call();
+        writeRegister8(DW1000_SYS_STATUS, 0, 0xF8);                 // clearing of sending status bits
+    }
+}
+
+uint16_t DW1000::getFramelength()
+{
+    uint16_t framelength = readRegister16(DW1000_RX_FINFO, 0);      // get framelength
+    framelength = (framelength & 0x03FF) - 2;                       // take only the right bits and subtract the 2 CRC Bytes
+    return framelength;
+}
+
+// SPI Interface ------------------------------------------------------------------------------------
+uint8_t DW1000::readRegister8(uint8_t reg, uint16_t subaddress)
+{
+    uint8_t result;
+    readRegister(reg, subaddress, &result, 1);
+    return result;
+}
+
+uint16_t DW1000::readRegister16(uint8_t reg, uint16_t subaddress)
+{
+    uint16_t result;
+    readRegister(reg, subaddress, (uint8_t*)&result, 2);
+    return result;
+}
+
+uint32_t DW1000::readRegister32(uint8_t reg, uint16_t subaddress)
+{
+    uint32_t result;
+    readRegister(reg, subaddress, (uint8_t*)&result, 4);
+    return result;
+}
+
+
+uint64_t DW1000::readRegister40(uint8_t reg, uint16_t subaddress)
+{
+    uint64_t result = 0;
+    readRegister(reg, subaddress, (uint8_t*)&result, 5);
+    return result;
+}
+uint64_t DW1000::readRegister64(uint8_t reg, uint16_t subaddress)
+{
+    uint64_t result;
+    readRegister(reg, subaddress, (uint8_t*)&result, 8);
+    return result;
+}
+
+void DW1000::writeRegister8(uint8_t reg, uint16_t subaddress, uint8_t buffer)
+{
+    writeRegister(reg, subaddress, &buffer, 1);
+}
+
+void DW1000::writeRegister16(uint8_t reg, uint16_t subaddress, uint16_t buffer)
+{
+    writeRegister(reg, subaddress, (uint8_t*)&buffer, 2);
+}
+
+void DW1000::writeRegister32(uint8_t reg, uint16_t subaddress, uint32_t buffer)
+{
+    writeRegister(reg, subaddress, (uint8_t*)&buffer, 4);
+}
+
+void DW1000::writeRegister40(uint8_t reg, uint16_t subaddress, uint64_t buffer)
+{
+    writeRegister(reg, subaddress, (uint8_t*)&buffer, 5);
+}
+
+void DW1000::readRegister(uint8_t reg, uint16_t subaddress, uint8_t *buffer, int length)
+{
+    setupTransaction(reg, subaddress, false);
+    for(int i=0; i<length; i++)                             // get data
+        buffer[i] = spi.write(0x00);
+    deselect();
+}
+
+void DW1000::writeRegister(uint8_t reg, uint16_t subaddress, uint8_t *buffer, int length)
+{
+    setupTransaction(reg, subaddress, true);
+    for(int i=0; i<length; i++)                             // put data
+        spi.write(buffer[i]);
+    deselect();
+}
+
+void DW1000::setupTransaction(uint8_t reg, uint16_t subaddress, bool write)
+{
+    reg |=  (write * DW1000_WRITE_FLAG);                                        // set read/write flag
+    select();
+    if (subaddress > 0) {                                                       // there's a subadress, we need to set flag and send second header byte
+        spi.write(reg | DW1000_SUBADDRESS_FLAG);
+        if (subaddress > 0x7F) {                                                // sub address too long, we need to set flag and send third header byte
+            spi.write((uint8_t)(subaddress & 0x7F) | DW1000_2_SUBADDRESS_FLAG); // and
+            spi.write((uint8_t)(subaddress >> 7));
+        } else {
+            spi.write((uint8_t)subaddress);
+        }
+    } else {
+        spi.write(reg);                                                         // say which register address we want to access
+    }
+}
+
+void DW1000::select()       // always called to start an SPI transmission
+{
+    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.
+    cs = 0;                 // set Cable Select pin low to start transmission
+}
+
+void DW1000::deselect()     // always called to end an SPI transmission
+{
+    cs = 1;                 // set Cable Select pin high to stop transmission
+    irq.enable_irq();       // reenable the interrupt handler
+}