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

Dependencies:   BurstSPI

DW1000.cpp

Committer:
AndyA
Date:
2016-08-01
Revision:
10:f1e3c04080d6
Parent:
9:326bf149c8bc
Child:
13:8718966cd81e

File content as of revision 10:f1e3c04080d6:

#include "DW1000.h"

#define SPIRATE_PLL (10*1000*1000)
#define SPIRATE_OSC (2*1000*1000)

DW1000::DW1000(PinName MOSI, PinName MISO, PinName SCLK, PinName CS, PinName IRQ) : irq(IRQ), spi(MOSI, MISO, SCLK), cs(CS)
{
    setCallbacks(NULL, NULL);
    DW1000Setup newSetup(DW1000Setup::tunedDefault);
    systemConfig.applyConfig(&newSetup);

    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)

    setupRadio();

    setRxDelay(0);
    setTxDelay(0);
}


DW1000Setup* DW1000::getSetup()
{
    return &systemConfig;
}

bool DW1000::applySetup(DW1000Setup *setup)
{

    if (setup->check()) {
        systemConfig.applyConfig(setup);
        setupRadio();
        spi.frequency(SPIRATE_PLL);             // with a 1MHz clock rate (worked up to 49MHz in our Test)
        return true;
    }
    return false;
}

void DW1000::setupRadio()
{
    irq.rise(NULL);       // attach interrupt handler to rising edge of interrupt pin from DW1000

    stopTRX();
    resetAll();                         // we do a soft reset of the DW1000 to get to a known state. Without this we lose comms.
    setupAGC();
    setupRxConfig();
    setupLDE();
    setupChannel();
    setupAnalogRF();
    setupFreqSynth();
    setupTxCalibration();
    setupTxFrameCtrl();
    setupSystemConfig();
    setupGPIO();
    setupPower();

    irq.rise(this, &DW1000::ISR);       // attach interrupt handler to rising edge of interrupt pin from DW1000
}


void DW1000::setupGPIO()
{
// not done in a loop because bits 7 and 8 are the inverse, a value of 01 indicates GPIO
    uint32_t value = 0;
    uint32_t pinMask = systemConfig.getGPIO();
    if (pinMask & (0x01<<0))
        value |= 1<<6;

    if (pinMask & (0x01<<1))
        value |= 1<<8;

    if (pinMask & (0x01<<2))
        value |= 1<<10;

    if (pinMask & (0x01<<3))
        value |= 1<<12;

    if (pinMask & (0x01<<4))
        value |= 1<<14;

    if (pinMask & (0x01<<5))
        value |= 1<<16;

    if (pinMask & (0x01<<6))
        value |= 1<<18;

    if (!(pinMask & (0x01<<7)))
        value |= 1<<20;

    if (!(pinMask & (0x01<<8)))
        value |= 1<<22;

    writeRegister32(DW1000_GPIO_CTRL, 0, value); // set time to 400ms, enable blink and flash all LEDs

    if (pinMask & 0x000f) { // some LEDs are active
        writeRegister32(DW1000_PMSC,DWPMSC_PMSC_CTRL0,readRegister32(DW1000_PMSC,DWPMSC_PMSC_CTRL0) | 1<<23 | 1<<18);
        writeRegister32(DW1000_PMSC, DWPMSC_PMSC_LEDC, 0x00000120); // set time to 400ms, enable blink and flash all LEDs
    }
}

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(float powerdB)
{
    // course power control - 0 = 18dB, 6 = 0dB in 3dB steps.
    uint8_t course = powerdB / 3;

    if(course > 6)
        course = 6;

    // remaining power
    powerdB -= course * 3;

    // value in reg is inverse.
    course = 6-course;

    // fine control in steps of 0.5dB
    uint8_t fine =  powerdB / 0.5f;
    if (fine > 31)
        fine = 31;

    return (course << 5) | fine;
}


float DW1000::regToPowerValue(uint8_t powerVal)
{

    int course = powerVal >> 5;
    if (course==7) // off
        return 0;

    course = (6-course)*3;

    int fine = (powerVal & 0x1f);

    return course + fine/2.0f;
}


void DW1000::setupPower()
{
    const float *powerPtr = systemConfig.getTxPowers();

    uint32_t powerReg = powerToRegValue(*powerPtr);
    powerReg |= powerToRegValue(*(powerPtr+1)) << 8;
    powerReg |= powerToRegValue(*(powerPtr+2)) << 16;
    powerReg |= powerToRegValue(*(powerPtr+3)) << 24;
    writeRegister32(DW1000_TX_POWER,0,powerReg);
}

// 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(float normalPowerdB, float boost500, float boost250, float boost125)
{
   
    if(normalPowerdB > 33.5)
        normalPowerdB = 33.5;

    if (boost500 < normalPowerdB)
        boost500 = normalPowerdB;
    if(boost500 > 33.5)
        boost500 = 33.5;

    if (boost250 < boost500)
        boost250 = boost500;
    if(boost250 > 33.5)
        boost250 = 33.5;

    if (boost125 < boost250)
        boost125 = boost250;
    if(boost125 > 33.5)
        boost125 = 33.5;

    if (systemConfig.getSmartPower() == false) {
        boost500 = normalPowerdB;
        boost250 = normalPowerdB;
        boost125 = normalPowerdB;
    }

    uint32_t powerReg = powerToRegValue(normalPowerdB);
    powerReg |= powerToRegValue(boost500) << 8;
    powerReg |= powerToRegValue(boost250) << 16;
    powerReg |= powerToRegValue(boost125) << 24;
    writeRegister32(DW1000_TX_POWER,0,powerReg);
    
    systemConfig.setSmartTxPower(normalPowerdB,boost500,boost250,boost125); // update the systemConfig
}

uint32_t DW1000::getTxPower(float *power,float *boost500, float *boost250, float*boost125)
{

    uint32_t value = readRegister32(DW1000_TX_POWER,0);
    if (power)
        *power = regToPowerValue(value&0x000000ff);
    if (boost500)
        *boost500 = regToPowerValue((value&0x0000ff00)>>8);
    if (boost250)
        *boost250 = regToPowerValue((value&0x00ff0000)>>16);
    if (boost125)
        *boost125 = regToPowerValue((value&0xff000000)>>24);
    return value;
}

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::getFullQualityMetrics(uint16_t *std_noise, uint16_t *fp_amp1, uint16_t *fp_amp2, uint16_t *fp_amp3,
                                        uint16_t *cir_pwr, uint16_t *preAmbleAcc, uint16_t *preAmbleAcc_NoSat)
{
    *fp_amp1 = readRegister16(DW1000_RX_TIME,7);
    *std_noise = readRegister16(DW1000_RX_FQUAL,0);
    *fp_amp2 = readRegister16(DW1000_RX_FQUAL,2);
    *fp_amp3 = readRegister16(DW1000_RX_FQUAL,4);
    *cir_pwr = readRegister16(DW1000_RX_FQUAL,6);
    *preAmbleAcc = readRegister16(DW1000_RX_FINFO,4) >> 4;
    *preAmbleAcc_NoSat = readRegister16(DW1000_DRX_CONF,DWDRX_RXPAC_NOSAT);
}

#define SQR(x) ((float)(x) * (float)(x))

void DW1000::getRxSignalPower(float *direct, float *total)
{
    uint16_t firstPathAmp1 = readRegister16(DW1000_RX_TIME,7);
    uint16_t firstPathAmp2 = readRegister16(DW1000_RX_FQUAL,2);
    uint16_t firstPathAmp3 = readRegister16(DW1000_RX_FQUAL,4);
    uint16_t preambleAcc = readRegister16(DW1000_RX_FINFO,4) >> 4;
    uint16_t preambleAccNoSat = readRegister16(DW1000_DRX_CONF,DWDRX_RXPAC_NOSAT);
    uint16_t channelImpulse = readRegister16(DW1000_RX_FQUAL,6);

    if (preambleAcc == preambleAccNoSat) {
        if (systemConfig.getSfd() == DW1000Setup::standard) {
            if (systemConfig.getDataRate() == DW1000Setup::kbps110)
                preambleAcc += -64;
            else
                preambleAcc += -5;
        } else {
            if (systemConfig.getDataRate() == DW1000Setup::kbps110)
                preambleAcc += -82;
            else
                preambleAcc += -10;
        }
    }


    float directPower = 10*log10(  (SQR(firstPathAmp1) + SQR(firstPathAmp2) + SQR(firstPathAmp3))/SQR(preambleAcc));

    float rxSignalPower = 10*log10( ((float)channelImpulse * (1<<17))/SQR(preambleAcc) );

    if (systemConfig.getPRF() == DW1000Setup::prf16MHz) {
        directPower -= 113.77;
        rxSignalPower -= 113.77;
    } else {
        directPower -= 121.74;
        rxSignalPower -= 121.74;
    }

    *direct = directPower;
    *total = rxSignalPower;

}


#undef SQR

void DW1000::getFirstPath(uint16_t *fp_amp2,uint16_t *fp_amp3)
{
    *fp_amp2 = readRegister16(DW1000_RX_FQUAL,2);
    *fp_amp3 = readRegister16(DW1000_RX_FQUAL,4);
}



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::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
}