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

Dependencies:   BurstSPI

Files at this revision

API Documentation at this revision

Comitter:
AndyA
Date:
Tue Apr 05 10:51:00 2016 +0000
Child:
1:dcbd071f38d5
Child:
2:ebbb05cbc417
Commit message:
My version of the DW1000 driver

Changed in this revision

DW1000.cpp Show annotated file Show diff for this revision Revisions of this file
DW1000.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DW1000.cpp	Tue Apr 05 10:51:00 2016 +0000
@@ -0,0 +1,497 @@
+#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
+            //Those values are for the 110kbps mode (5, 16MHz, 1024 Symbols) and are quite complete
+            writeRegister16(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE1, 0x8870);             //AGC_TUNE1 for 16MHz PRF
+            writeRegister32(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE2, 0x2502A907);         //AGC_TUNE2 (Universal)
+            writeRegister16(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE3, 0x0055);             //AGC_TUNE3 (Universal)
+
+            writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE0B, 0x000A);             //DRX_TUNE0b for 110kbps
+            writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE1A, 0x0087);             //DRX_TUNE1a for 16MHz PRF
+            writeRegister16(DW1000_DRX_CONF, DWDRX_DRX_TUNE1B, 0x0064);             //DRX_TUNE1b for 110kbps & > 1024 symbols
+            writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x351A009A);         //PAC size for 1024 symbols preamble & 16MHz PRF
+            //writeRegister32(DW1000_DRX_CONF, 0x08, 0x371A011D);               //PAC size for 2048 symbols preamble
+
+            writeRegister8 (DW1000_LDE_CTRL, DWLDE_LDE_CFG1, 0xD);              //LDE_CFG1
+            writeRegister16(DW1000_LDE_CTRL, DWLDE_LDE_CFG2, 0x1607);           //LDE_CFG2 for 16MHz PRF
+
+            writeRegister32(DW1000_TX_POWER, 0, 0x28282828);            //Power for channel 5
+
+            writeRegister8(DW1000_RF_CONF, DWRFCONF_RF_RXCTRLH, 0xD8);                 //RF_RXCTRLH for channel 5
+            writeRegister32(DW1000_RF_CONF, DWRFCONF_RF_TXCTRL, 0x001E3FE0);          //RF_TXCTRL for channel 5
+
+            writeRegister8 (DW1000_TX_CAL, DWTXCAL_TC_PGDELAY, 0xC0);                 //TC_PGDELAY for channel 5
+
+            writeRegister32 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLCFG, 0x0800041D);         //FS_PLLCFG for channel 5
+            writeRegister8 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLTUNE, 0xBE); // changed from 0xA6                 //FS_PLLTUNE for channel 5
+
+            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
+
+            // 110kbps CAUTION: a lot of other registers have to be set for an optimized operation on 110kbps
+            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
+            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...]
+
+            writeRegister16(DW1000_TX_ANTD, 0, 16384); // set TX and RX Antenna delay to neutral because we calibrate afterwards
+            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)
+            break;
+
+        case tunedDefault:    // User Manual "2.5.5 Default Configurations that should be modified" p. 22
+            //Those values are for the standard mode (6.8Mbps, 5, 16Mhz, 32 Symbols) and are (may be?) INCOMPLETE!
+            writeRegister16(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE1, 0x8870);
+            writeRegister32(DW1000_AGC_CTRL, DWAGCCTRL_AGC_TUNE2, 0x2502A907);
+            writeRegister32(DW1000_DRX_CONF, DWDRX_DRX_TUNE2, 0x311A002D);
+            writeRegister8(DW1000_DRX_CONF, DWDRX_DRX_TUNE0B, 0x0001);
+            writeRegister8(DW1000_DRX_CONF, DWDRX_DRX_TUNE1A, 0x0087);
+            writeRegister8(DW1000_DRX_CONF, DWDRX_DRX_TUNE1B, 0x0020);
+            writeRegister8 (DW1000_LDE_CTRL, DWLDE_LDE_CFG1, 0xD);
+            writeRegister16(DW1000_LDE_CTRL, DWLDE_LDE_CFG2, 0x1607);
+            writeRegister32(DW1000_TX_POWER, 0, 0x0E082848);
+//            writeRegister32(DW1000_TX_POWER, 0, 0x75757575);
+            writeRegister32(DW1000_RF_CONF, DWRFCONF_RF_TXCTRL, 0x001E3FE0);
+            writeRegister8 (DW1000_TX_CAL, DWTXCAL_TC_PGDELAY, 0xC0);
+            writeRegister8 (DW1000_FS_CTRL, DWFSCTRL_FS_PLLTUNE, 0xBE);
+
+            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
+
+            writeRegister32(DW1000_GPIO_CTRL,DWGPIO_GPIO_MODE,0x00001400);
+            writeRegister16(DW1000_PMSC,DWPMSC_PMSC_LEDC,0x0120);
+
+//            writeRegister8(DW1000_SYS_CFG, 3, 0x20);    // enable auto RX reenable
+
+            setRxDelay(0);
+            setTxDelay(0);
+
+            break;
+        case defaultConfig:
+        default:
+            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
+            break;
+    }
+
+    writeRegister8(DW1000_SYS_CFG, 3, 0x20);    // enable auto reenabling receiver after error
+
+    irq.rise(this, &DW1000::ISR);       // attach interrupt handler to rising edge of interrupt pin from DW1000
+}
+
+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 - readOTP8(0x08)) *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 - readOTP8(0x09))*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 = readOTP40(0x0004);
+    if (LDOTuningValue != 0)
+        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 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,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 (readOTP32(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, uint8_t size) {
+    if (size == 1)
+      return readOTP8(word_address);
+    else if (size == 2)
+      return readOTP16(word_address);
+    else
+      return readOTP32(word_address);   
+    }
+
+
+uint32_t DW1000::readOTP32(uint16_t address)
+{
+    writeRegister16(DW1000_OTP_IF,DWOTP_OTP_ADDR,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;
+}
+
+uint8_t DW1000::readOTP8(uint16_t address)
+{
+    writeRegister16(DW1000_OTP_IF,DWOTP_OTP_ADDR,address); // write address
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x03);  // read address load
+    writeRegister8(DW1000_OTP_IF,DWOTP_OTP_CTRL,0x01);  // read
+    uint8_t data = readRegister8(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
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DW1000.h	Tue Apr 05 10:51:00 2016 +0000
@@ -0,0 +1,248 @@
+// by Matthias Grob & Manuel Stalder - ETH Zürich - 2015
+
+#ifndef DW1000_H
+#define DW1000_H
+
+#include "mbed.h"
+
+// register addresses
+//      Mnemonic                    Address Bytes Description
+#define DW1000_DEV_ID               0x00 //     4 Device Identifier – includes device type and revision information
+#define DW1000_EUI                  0x01 //     8 Extended Unique Identifier
+#define DW1000_PANADR               0x03 //     4 PAN Identifier and Short Address
+#define DW1000_SYS_CFG              0x04 //     4 System Configuration bitmap
+#define DW1000_SYS_TIME             0x06 //     5 System Time Counter (40-bit)
+#define DW1000_TX_FCTRL             0x08 //     5 Transmit Frame Control
+#define DW1000_TX_BUFFER            0x09 //  1024 Transmit Data Buffer
+#define DW1000_DX_TIME              0x0A //     5 Delayed Send or Receive Time (40-bit)
+#define DW1000_RX_FWTO              0x0C //     2 Receive Frame Wait Timeout Period
+#define DW1000_SYS_CTRL             0x0D //     4 System Control Register
+#define DW1000_SYS_MASK             0x0E //     4 System Event Mask Register
+#define DW1000_SYS_STATUS           0x0F //     5 System Event Status Register
+#define DW1000_RX_FINFO             0x10 //     4 RX Frame Information                (in double buffer set)
+#define DW1000_RX_BUFFER            0x11 //  1024 Receive Data Buffer                 (in double buffer set)
+#define DW1000_RX_FQUAL             0x12 //     8 Rx Frame Quality information        (in double buffer set)
+#define DW1000_RX_TTCKI             0x13 //     4 Receiver Time Tracking Interval     (in double buffer set)
+#define DW1000_RX_TTCKO             0x14 //     5 Receiver Time Tracking Offset       (in double buffer set)
+#define DW1000_RX_TIME              0x15 //    14 Receive Message Time of Arrival     (in double buffer set)
+#define DW1000_TX_TIME              0x17 //    10 Transmit Message Time of Sending    (in double buffer set)
+#define DW1000_TX_ANTD              0x18 //     2 16-bit Delay from Transmit to Antenna
+#define DW1000_SYS_STATE            0x19 //     5 System State information
+#define DW1000_ACK_RESP_T           0x1A //     4 Acknowledgement Time and Response Time
+#define DW1000_RX_SNIFF             0x1D //     4 Pulsed Preamble Reception Configuration
+#define DW1000_TX_POWER             0x1E //     4 TX Power Control
+#define DW1000_CHAN_CTRL            0x1F //     4 Channel Control
+#define DW1000_USR_SFD              0x21 //    41 User-specified short/long TX/RX SFD sequences
+#define DW1000_AGC_CTRL             0x23 //    32 Automatic Gain Control configuration
+#define DW1000_EXT_SYNC             0x24 //    12 External synchronisation control.
+#define DW1000_ACC_MEM              0x25 //  4064 Read access to accumulator data
+#define DW1000_GPIO_CTRL            0x26 //    44 Peripheral register bus 1 access - GPIO control
+#define DW1000_DRX_CONF             0x27 //    44 Digital Receiver configuration
+#define DW1000_RF_CONF              0x28 //    58 Analog RF Configuration
+#define DW1000_TX_CAL               0x2A //    52 Transmitter calibration block
+#define DW1000_FS_CTRL              0x2B //    21 Frequency synthesiser control block
+#define DW1000_AON                  0x2C //    12 Always-On register set
+#define DW1000_OTP_IF               0x2D //    18 One Time Programmable Memory Interface
+#define DW1000_LDE_CTRL             0x2E //     - Leading edge detection control block
+#define DW1000_DIG_DIAG             0x2F //    41 Digital Diagnostics Interface
+#define DW1000_PMSC                 0x36 //    48 Power Management System Control Block
+
+// AGC_CTRL sub registers
+#define DWAGCCTRL_AGC_CTRL1         0x02
+#define DWAGCCTRL_AGC_TUNE1         0x04
+#define DWAGCCTRL_AGC_TUNE2         0x0C
+#define DWAGCCTRL_AGC_TUNE3         0x12
+
+// EXT_SYNC sub registers
+#define DWEXTSYNC_EC_CTRL           0x00
+#define DWEXTSYNC_EC_RXTC           0x04
+#define DWEXTSYNC_EC_GOLP           0x08
+
+// GPIO sub registers
+#define DWGPIO_GPIO_MODE           0x00
+#define DWGPIO_GPIO_DIR            0x08
+#define DWGPIO_GPIO_DOUT           0x0C
+#define DWGPIO_GPIO_IRQE           0x10
+#define DWGPIO_GPIO_ISEN           0x14
+#define DWGPIO_GPIO_IMODE          0x18
+#define DWGPIO_GPIO_IBES           0x1C
+#define DWGPIO_GPIO_ICLR           0x20
+#define DWGPIO_GPIO_IDBE           0x24
+#define DWGPIO_GPIO_RAW            0x28
+
+// DRX sub registers
+#define DWDRX_DRX_TUNE0B            0x02
+#define DWDRX_DRX_TUNE1A            0x04
+#define DWDRX_DRX_TUNE1B            0x06
+#define DWDRX_DRX_TUNE2             0x08
+#define DWDRX_DRX_SFDTOC            0x20
+#define DWDRX_DRX_PRETOC            0x24
+#define DWDRX_DRX_TUNE4H            0x26
+
+//RF conf sub registers
+#define DWRFCONF_RF_CONF            0x00
+#define DWRFCONF_RF_RXCTRLH         0x0B
+#define DWRFCONF_RF_TXCTRL          0x0C
+#define DWRFCONF_RF_STATUS          0x2C
+#define DWRFCONF_RF_LDOTUNE         0x30
+
+// TX cal sub registers
+#define DWTXCAL_TC_SARC             0x00
+#define DWTXCAL_TC_SARL             0x03
+#define DWTXCAL_TC_SARW             0x06
+#define DWTXCAL_TC_PGDELAY          0x0B
+#define DWTXCAL_TC_PGTEST           0x0C
+
+// Freq synth sub registers
+#define DWFSCTRL_FS_PLLCFG          0x07
+#define DWFSCTRL_FS_PLLTUNE         0x0B
+#define DWFSCTRL_FS_XTALT           0x0E
+
+// Always on sub registers
+#define DWAON_AON_WCFG              0x00
+#define DWAON_AON_CTRL              0x02
+#define DWAON_AON_RDAT              0x03
+#define DWAON_AON_ADDR              0x04
+#define DWAON_AON_CFG0              0x06
+#define DWAON_AON_CFG1              0x0A
+
+// OTP sub registers
+#define DWOTP_OTP_WDAT              0x00
+#define DWOTP_OTP_ADDR              0x04
+#define DWOTP_OTP_CTRL              0x06
+#define DWOTP_OTP_STAT              0x08
+#define DWOTP_OTP_RDAT              0x0A
+#define DWOTP_OTP_SRDAT             0x0E
+#define DWOTP_OTP_SF                0x12
+
+//LDE_IF sub registers
+#define DWLDE_LDE_THRESH            0x0000
+#define DWLDE_LDE_CFG1              0x0806
+#define DWLDE_LDE_PPINDX            0x1000
+#define DWLDE_LDE_PPAMPL            0x1002
+#define DWLDE_LDE_RXANTD            0x1804
+#define DWLDE_LDE_CFG2              0x1806
+#define DWLDE_LDE_REPC              0x2804
+
+// Dig Diag sub registers
+#define DWDIAG_EVC_CTRL             0x00
+#define DWDIAG_EVC_PHE              0x04
+#define DWDIAG_EVC_RSE              0x06
+#define DWDIAG_EVC_FCG              0x08
+#define DWDIAG_EVC_FCE              0x0A
+#define DWDIAG_EVC_FFR              0x0C
+#define DWDIAG_EVC_OVR              0x0E
+#define DWDIAG_EVC_STO              0x10
+#define DWDIAG_EVC_PTO              0x12
+#define DWDIAG_EVC_FWTO             0x14
+#define DWDIAG_EVC_TXFS             0x16
+#define DWDIAG_EVC_HPW              0x18
+#define DWDIAG_EVC_TPW              0x1A
+#define DWDIAG_DIAG_TMC             0x24
+
+// power control sub registers
+#define DWPMSC_PMSC_CTRL0           0x00
+#define DWPMSC_PMSC_CTRL1           0x04
+#define DWPMSC_PMSC_SNOZT           0x0C
+#define DWPMSC_PMSC_TXFSEQ          0x26
+#define DWPMSC_PMSC_LEDC            0x28
+
+
+#define DW1000_WRITE_FLAG           0x80 // First Bit of the address has to be 1 to indicate we want to write
+#define DW1000_SUBADDRESS_FLAG      0x40 // if we have a sub address second Bit has to be 1
+#define DW1000_2_SUBADDRESS_FLAG    0x80 // if we have a long sub adress (more than 7 Bit) we set this Bit in the first part
+
+typedef enum {defaultConfig, tunedDefault, user110k} UWBMode;
+
+class DW1000
+{
+public:
+
+    DW1000(UWBMode setup, PinName MOSI, PinName MISO, PinName SCLK, PinName CS, PinName IRQ);              // constructor, uses SPI class
+    void setCallbacks(void (*callbackRX)(void), void (*callbackTX)(void));                  // setter for callback functions, automatically enables interrupt, if NULL is passed the coresponding interrupt gets disabled
+    template<typename T>
+    void setCallbacks(T* tptr, void (T::*mptrRX)(void), void (T::*mptrTX)(void)) {      // overloaded setter to treat member function pointers of objects
+        callbackRX.attach(tptr, mptrRX);                                                    // possible client code: dw.setCallbacks(this, &A::callbackRX, &A::callbackTX);
+        callbackTX.attach(tptr, mptrTX);                                                    // concept seen in line 100 of http://developer.mbed.org/users/mbed_official/code/mbed/docs/4fc01daae5a5/InterruptIn_8h_source.html
+        setInterrupt(true,true);
+    }
+
+    // Device API
+    uint32_t getDeviceID();                                                                 // gets the Device ID which should be 0xDECA0130 (good for testing SPI!)
+    uint64_t getEUI();                                                                      // gets 64 bit Extended Unique Identifier according to IEEE standard
+    void setEUI(uint64_t EUI);                                                              // sets 64 bit Extended Unique Identifier according to IEEE standard
+    float getVoltage();                                                                     // gets the current chip voltage measurement form the A/D converter
+    float getTemperature();                                                                 // gets the current chip temperature measurement form the A/D converter
+    uint64_t getStatus();                                                                   // get the 40 bit device status
+    uint64_t getRXTimestamp();
+    uint64_t getTXTimestamp();
+
+    void sendString(char* message);                                                         // to send String with arbitrary length
+    void receiveString(char* message);                                                      // to receive char string (length of the buffer must be 1021 to be safe)
+    void sendFrame(uint8_t* message, uint16_t length);                                      // send a raw frame (length in bytes)
+    void sendDelayedFrame(uint8_t* message, uint16_t length, uint64_t TxTimestamp);
+
+    void setupSyncedFrame(uint8_t* message, uint16_t length);
+    void armSyncedFrame();
+
+    void startRX();                                                                         // start listening for frames
+    void stopTRX();                                                                         // disable tranceiver go back to idle mode
+
+    void setRxDelay(uint16_t ticks);
+    void setTxDelay(uint16_t ticks);
+
+    uint16_t getFramelength();                                                              // to get the framelength of the received frame from the PHY header
+
+    void readRxBuffer( uint8_t *buffer, int length ) {
+        readRegister(DW1000_RX_BUFFER, 0, buffer, length);
+    }
+
+    uint32_t readOTP (uint16_t word_address, uint8_t size);
+    bool writeOTP(uint16_t word_address,uint32_t data);                                          // program a value in the OTP. It is recommended to reset afterwards.
+
+protected:
+    void resetRX();                                                                         // soft reset only the tranciever part of DW1000
+    void setInterrupt(bool RX, bool TX);                                                    // set Interrupt for received a good frame (CRC ok) or transmission done
+
+
+private:
+    void resetAll();                                                                        // soft reset the entire DW1000 (some registers stay as they were see User Manual)
+    void loadLDE();                                                                         // load the leading edge detection algorithm to RAM, [IMPORTANT because receiving malfunction may occur] see User Manual LDELOAD on p22 & p158
+    void loadLDOTUNE();                                                                     // load the LDO tuning as set in the factory
+
+
+    // Interrupt
+    InterruptIn irq;                                                                        // Pin used to handle Events from DW1000 by an Interrupthandler
+    FunctionPointer callbackRX;                                                             // function pointer to callback which is called when successfull RX took place
+    FunctionPointer callbackTX;                                                             // function pointer to callback which is called when successfull TX took place
+    void ISR();                                                                             // interrupt handling method (also calls according callback methods)
+
+
+    // OTP
+    uint8_t readOTP8(uint16_t address);
+    uint32_t readOTP32(uint16_t address);
+    uint64_t readOTP64(uint16_t address);
+    uint64_t readOTP40(uint16_t address);
+
+    // SPI Inteface
+    SPI spi;                                                                                // SPI Bus
+    DigitalOut cs;                                                                          // Slave selector for SPI-Bus (here explicitly needed to start and end SPI transactions also usable to wake up DW1000)
+
+    uint8_t readRegister8(uint8_t reg, uint16_t subaddress);                                // expressive methods to read or write the number of bits written in the name
+    uint16_t readRegister16(uint8_t reg, uint16_t subaddress);
+    uint32_t readRegister32(uint8_t reg, uint16_t subaddress);
+    uint64_t readRegister40(uint8_t reg, uint16_t subaddress);
+    uint64_t readRegister64(uint8_t reg, uint16_t subaddress);
+    void writeRegister8(uint8_t reg, uint16_t subaddress, uint8_t buffer);
+    void writeRegister16(uint8_t reg, uint16_t subaddress, uint16_t buffer);
+    void writeRegister32(uint8_t reg, uint16_t subaddress, uint32_t buffer);
+    void writeRegister40(uint8_t reg, uint16_t subaddress, uint64_t buffer);
+
+    void readRegister(uint8_t reg, uint16_t subaddress, uint8_t *buffer, int length);       // reads the selected part of a slave register into the buffer memory
+    void writeRegister(uint8_t reg, uint16_t subaddress, uint8_t *buffer, int length);      // writes the buffer memory to the selected slave register
+    void setupTransaction(uint8_t reg, uint16_t subaddress, bool write);                    // sets up an SPI read or write transaction with correct register address and offset
+    void select();                                                                          // selects the only slave for a transaction
+    void deselect();                                                                        // deselects the only slave after transaction
+};
+
+#endif
\ No newline at end of file