Skip to content
Snippets Groups Projects
dw1000.c 13 KiB
Newer Older
#include "dw1000.h"
#include "dw1000_hal.h"
#include "deca_regs.h"
#include "Trace.h"

#define LDOTUNE_ADDRESS (0x04)
#define PARTID_ADDRESS (0x06)
#define LOTID_ADDRESS  (0x07)
#define VBAT_ADDRESS   (0x08)
#define VTEMP_ADDRESS  (0x09)
#define TXCFG_ADDRESS  (0x10)
#define ANTDLY_ADDRESS (0x1C)
#define XTRIM_ADDRESS  (0x1E)


int dw1000_init(uint16_t config, BaseType_t (*sendCallback)(),
		BaseType_t (*receiveCallback)(uint32_t bufferLength)) {


	// Clear control-structure
	//memset(&dw1000local, 0, sizeof(dw1000_local_data_t));

	// Callbacks
	dw1000local.sendCB = sendCallback;
	dw1000local.receiveCB = receiveCallback;

	// Initialize HAL
	dw1000Hal_init();

	// Soft-Reset
	dw1000Util_reset();


	// Set allowed interrupts
	uint32_t sys_mask = 0;
	dw1000Hal_readRegister(SYS_MASK_ID, (uint8_t *) &sys_mask, SYS_MASK_LEN);
	trace_printf("SYS_MASK: %x\n", sys_mask);
	sys_mask |= ( SYS_MASK_MTXFRS | SYS_MASK_MRXDFR | SYS_MASK_MRXFCG
			);
	trace_printf("SYS_MASK: %x\n", sys_mask);
	dw1000Hal_writeRegister(SYS_MASK_ID, (uint8_t *) &sys_mask, SYS_MASK_LEN);

	//set TX LED
	uint32_t gpio = 0x5540; //equiv to MSGP0 = 01, MSGP1 = 01, MSGP2 = 01, MSGP3 = 01, enables LED for rec and sending
	dw1000Hal_writeSubRegister(GPIO_CTRL_ID, GPIO_MODE_OFFSET, (uint8_t*) &gpio,
	GPIO_MODE_LEN);
	uint32_t led = 0;
	dw1000Hal_readSubRegister(PMSC_ID, PMSC_CTRL0_OFFSET, (uint8_t*) &led,
	PMSC_CTRL0_LEN);
	led |= (1 << 18) | (1 << 23); // Preparing LEDs for blink mode
	dw1000Hal_writeSubRegister(PMSC_ID, PMSC_CTRL0_OFFSET, (uint8_t*) &led,
	PMSC_CTRL0_LEN);
	dw1000Hal_readSubRegister(PMSC_ID, PMSC_LEDC_OFFSET, (uint8_t*) &led,
	PMSC_LEDC_LEN);
	led |= PMSC_LEDC_BLNKEN; // enable blink mode
	led |= 0xF0000; 		 // force leds to blink once
	dw1000Hal_writeSubRegister(PMSC_ID, PMSC_LEDC_OFFSET, (uint8_t*) &led,
	PMSC_LEDC_LEN);
	led &= ~0xF0000; // reset froce blink bits. needed to make the leds blinking
	dw1000Hal_writeSubRegister(PMSC_ID, PMSC_LEDC_OFFSET, (uint8_t*) &led,
	PMSC_LEDC_LEN);

	//DECA: set system clock to XTI - this is necessary to make sure the values read by _dwt_otpread are reliable
	dw1000Util_enableclocks(FORCE_SYS_XTI);

	 if(config & DWT_LOADLDOTUNE)
	 {
	 dw1000local.ldoTune = dw1000Util_otpread(LDOTUNE_ADDRESS);
	 }

	if ((dw1000local.ldoTune & 0xFF) != 0) //LDO tune values are stored in the OTP
			{
		uint8_t ldok = OTP_SF_LDO_KICK;
		//kick LDO tune
//		dwt_writetodevice(OTP_IF_ID, OTP_SF, 1, &ldok); // set load LDO kick bit
		dw1000Hal_writeSubRegister(OTP_IF_ID, OTP_SF, &ldok, 1);
	} else {
		dw1000local.ldoTune = 0;
	}

	/* TODO: partID, lotID sinnvoll?
	 dw1000local.partID = _dwt_otpread(PARTID_ADDRESS);
	 dw1000local.lotID = _dwt_otpread(LOTID_ADDRESS);
	 */


	// load leading edge detect code
	if (config & DWT_LOADUCODE) {
		uint8_t wr_buf[2];

		//set up clocks
		wr_buf[1] = 0x03; //Force TX clock off.
		wr_buf[0] = 0x01; //Force system clock to be the 19.2 MHz XTI clock.
		//DECA:dwt_writetodevice(PMSC_ID, PMSC_CTRL0_OFFSET, 2, wr_buf);
		dw1000Hal_writeSubRegister(PMSC_ID, PMSC_CTRL0_OFFSET, wr_buf, 2); //Just first 2 byte instead of whole crtl0
		//kick off the LDE load
		//DECA:dwt_write16bitoffsetreg(OTP_IF_ID, OTP_CTRL, OTP_CTRL_LDELOAD); // set load LDE kick bit
		uint16_t otp_ctrl_ldeload = OTP_CTRL_LDELOAD;
		dw1000Hal_writeSubRegister(OTP_IF_ID, OTP_CTRL,
				(uint8_t *) &otp_ctrl_ldeload, 2);

		//FIXME: Sleep in FreeRTOS? Sleep(1); // Allow time for code to upload (should take up to 120 us)

		//default clocks (ENABLE_ALL_SEQ)
		//DECA:enable clocks for sequencing
		dw1000Util_enableclocks(ENABLE_ALL_SEQ);
	} else //should disable the LDERUN enable bit in 0x36, 0x4
	{
		//DECA: uint16_t rega = dwt_read16bitoffsetreg(PMSC_ID, PMSC_CTRL1_OFFSET+1) ;
		uint32_t reg = 0;
		dw1000Hal_readSubRegister(PMSC_ID, PMSC_CTRL1_OFFSET, (uint8_t *) &reg,
				PMSC_CTRL1_LEN);
		//clear LDERUN bit
		reg &= 0xFFFDFFFF;
		dw1000Hal_writeSubRegister(PMSC_ID, PMSC_CTRL1_OFFSET, (uint8_t *) &reg,
				PMSC_CTRL1_LEN);
	}


	//DECA:enable clocks for sequencing
	//Very important! Not sending on FORCE_SYS_XTI
	dw1000Util_enableclocks(ENABLE_ALL_SEQ);
	//DECA: read system register / store local copy
	dw1000Hal_readRegister(SYS_CFG_ID, (uint8_t *) &dw1000local.sysCFGreg,
	SYS_CFG_LEN);


	uint32_t event_clear = 0xFFFFFFFF;
	dw1000Hal_writeRegister(SYS_STATUS_ID, (uint8_t*) &event_clear,
	SYS_STATUS_LEN);


	//Enable Receiver
	dw1000Util_enableRX();

	return 0;
}

int dw1000_configure(dwt_config_t *config, uint8_t use_otpconfigvalues) {
	uint8_t nsSfd_result = 0;
	uint8_t useDWnsSFD = 0;
	uint8_t chan = config->chan;
	uint32_t regval;
	uint16_t reg16 = lde_replicaCoeff[config->rxCode];
	uint8_t prfIndex = dw1000local.prfIndex = config->prf - DWT_PRF_16M;
	uint8_t bw = ((chan == 4) || (chan == 7)) ? 1 : 0; //select wide or narrow band

	dw1000local.chan = config->chan;

	// DECA: for 110 kbps we need to special setup
	if (DWT_BR_110K == config->dataRate) {
		dw1000local.sysCFGreg |= SYS_CFG_RXM110K;

		reg16 >>= 3;  //div by 8 According to Page 170
	} else {
		dw1000local.sysCFGreg &= (~SYS_CFG_RXM110K);
	}
	dw1000local.longFrames = config->phrMode;

	dw1000local.sysCFGreg |= (SYS_CFG_PHR_MODE_11 & (config->phrMode << 16)); //Set to enable PhyHdr for long frames

	dw1000local.sysCFGreg |= (1 << 29); //RXAUTR

	dw1000Hal_writeRegister(SYS_CFG_ID, (uint8_t *) &dw1000local.sysCFGreg,
	SYS_CFG_LEN);

	//DECA:write/set the lde_replicaCoeff
	dw1000Hal_writeSubRegister(LDE_IF_ID, LDE_REPC_OFFSET, (uint8_t *) &reg16,
			2); //Page 169

	//configure LDE algorithm parameters
	uint8_t x = LDE_PARAM1; //TODO WHAT??
	/*8-bit configuration register*/
	dw1000Hal_writeSubRegister(LDE_IF_ID, LDE_CFG1_OFFSET, &x, 1);

	uint16_t lde_param3;
	if (prfIndex) {
		lde_param3 = (uint16_t) LDE_PARAM3_64;
	} else {
		lde_param3 = (uint16_t) LDE_PARAM3_16;
	}
	dw1000Hal_writeSubRegister(LDE_IF_ID, LDE_CFG2_OFFSET,
			(uint8_t *) &lde_param3, 2);

	//    config RF pll (for a given channel)
	//    configure PLL2/RF PLL block CFG
	//DECA: dwt_writetodevice(FS_CTRL_ID, FS_PLLCFG_OFFSET, 5, &pll2_config[chan_idx[chan]][0]);
	//Configure FS_PLLTUNE too
	dw1000Hal_writeSubRegister(FS_CTRL_ID, FS_PLLCFG_OFFSET,
			(uint8_t *) &pll2_config[chan_idx[chan]][0], FS_PLLCFG_LEN);

	//DECA: configure PLL2/RF PLL block CAL
	//Crystal Oscillator Trim
	dw1000Hal_writeSubRegister(FS_CTRL_ID, FS_XTALT_OFFSET,
			(uint8_t *) &pll2calcfg, 1);

	//DECA: Configure RF RX blocks (for specified channel/bandwidth)
	dw1000Hal_writeSubRegister(RF_CONF_ID, RF_RXCTRLH_OFFSET,
			(uint8_t *) &rx_config[bw], 1);

	//DECA: Configure RF TX blocks (for specified channel and prf)
	//DECA: Config RF TX control
	dw1000Hal_writeSubRegister(RF_CONF_ID, RF_TXCTRL_OFFSET,
			(uint8_t *) &tx_config[chan_idx[chan]], RF_TXCTRL_LEN);

	//DECA: Configure the baseband parameters (for specified prf, bit rate, pac, and SFD settings)
	//DECA:DTUNE0
	dw1000Hal_writeSubRegister(DRX_CONF_ID, DRX_TUNE0b_OFFSET,
			(uint8_t *) &sftsh[config->dataRate][config->nsSFD],
			DRX_TUNE0b_LEN);

	//DTUNE1 FIXME: Führt zu Abbruch vom Senden, bei zulangen ISR oder zu vielen interrupts
	dw1000Hal_writeSubRegister(DRX_CONF_ID, DRX_TUNE1a_OFFSET,
			(uint8_t *) &dtune1[prfIndex], DRX_TUNE1a_LEN);

	if (config->dataRate == DWT_BR_110K) {
		uint16_t reg = 0x64;
		dw1000Hal_writeSubRegister(DRX_CONF_ID, DRX_TUNE1b_OFFSET,
				(uint8_t *) &reg, DRX_TUNE1b_LEN);
		//TODO: Hier kein DRX_DRX_TUNE4HOFFSET setzen?

	} else {
		if (config->txPreambLength == DWT_PLEN_64) //if preamble length is 64
		{
			uint8_t temp = 0x10;
			dw1000Hal_writeSubRegister(DRX_CONF_ID, DRX_TUNE1b_OFFSET,
					(uint8_t *) &temp, DRX_TUNE1b_LEN);
			dw1000Hal_writeSubRegister(DRX_CONF_ID, DRX_DRX_TUNE4HOFFSET,
					(uint8_t *) &temp, 1);
		} else {
			uint8_t temp = 0x20;
			//DECA: dwt_write16bitoffsetreg(DRX_CONF_ID, DRX_TUNE1b_OFFSET, 0x20);
			dw1000Hal_writeSubRegister(DRX_CONF_ID, DRX_TUNE1b_OFFSET,
					(uint8_t *) &temp, DRX_TUNE1b_LEN);
			temp = 0x28;
			//DECA: dwt_writetodevice(DRX_CONF_ID, 0x26, 1, &temp);
			dw1000Hal_writeSubRegister(DRX_CONF_ID, DRX_DRX_TUNE4HOFFSET,
					(uint8_t *) &temp, 1);

		}
	}

//	//DTUNE2
//	dw1000Hal_writeSubRegister(DRX_CONF_ID, DRX_TUNE2_OFFSET,
//			(uint8_t *) &digital_bb_config[prfIndex][config->rxPAC],
//			DRX_TUNE2_LEN);
//
//	uint32_t temp;
//	dw1000Hal_readSubRegister(DRX_CONF_ID, DRX_TUNE2_OFFSET,
//			(uint8_t *) &temp,
//			DRX_TUNE2_LEN);
//
////#ifdef DEBUG
////	hexdump(&temp, 4);
////#endif



	//DTUNE3 set SFD detection timeout count
	if (config->sfdTO != DWT_SFDTOC_DEF) { //if default value no need to program it
		dw1000Hal_writeSubRegister(DRX_CONF_ID, DRX_SFDTOC_OFFSET,
				(uint8_t *) &config->sfdTO, DRX_SFDTOC_LEN);
	}
	//don't allow 0 - SFD timeout will always be enabled
	if (config->sfdTO == 0) {
		uint16_t tmp = DWT_SFDTOC_DEF;
		dw1000Hal_writeSubRegister(DRX_CONF_ID, DRX_SFDTOC_OFFSET,
				(uint8_t *) &tmp, DRX_SFDTOC_LEN);
	}

	/* TODO notwendig? was tut dies?
	 // configure AGC parameters
	 dwt_write32bitoffsetreg( AGC_CFG_STS_ID, 0xC, agc_config.lo32);
	 dwt_write16bitoffsetreg( AGC_CFG_STS_ID, 0x4, agc_config.target[prfIndex]);
	 */

	//DECA: set (non-standard) user SFD for improved performance,
	if (config->nsSFD) {
		//Write non standard (DW) SFD length
		dw1000Hal_writeSubRegister(USR_SFD_ID, 0x00,
				(uint8_t *) &dwnsSFDlen[config->dataRate], 1);
		nsSfd_result = 3;
		useDWnsSFD = 1;
	}

	//Set CHAN_CTRL, Channel Number etc
	regval = (CHAN_CTRL_TX_CHAN_MASK & (chan << CHAN_CTRL_TX_CHAN_SHIFT)) | // Transmit Channel
			(CHAN_CTRL_RX_CHAN_MASK & (chan << CHAN_CTRL_RX_CHAN_SHIFT)) | // Receive Channel
			(CHAN_CTRL_RXFPRF_MASK & (config->prf << CHAN_CTRL_RXFPRF_SHIFT)) | // RX PRF
			((CHAN_CTRL_TNSSFD | CHAN_CTRL_RNSSFD)
					& (nsSfd_result << CHAN_CTRL_TNSSFD_SHIFT)) | // nsSFD enable RX&TX
			(CHAN_CTRL_DWSFD & (useDWnsSFD << CHAN_CTRL_DWSFD_SHIFT)) | // use DW nsSFD
			(CHAN_CTRL_TX_PCOD_MASK
					& (config->txCode << CHAN_CTRL_TX_PCOD_SHIFT)) | // TX Preamble Code
			(CHAN_CTRL_RX_PCOD_MASK
					& (config->rxCode << CHAN_CTRL_RX_PCOD_SHIFT)); // RX Preamble Code

	dw1000Hal_writeRegister(CHAN_CTRL_ID, (uint8_t *) &regval, CHAN_CTRL_LEN);

	// Set up TX Preamble Size and TX PRF
	// Set up TX Ranging Bit and Data Rate
	{
		uint32_t x = (config->txPreambLength | config->prf) << 16;
		dw1000local.txFCTRL = x | TX_FCTRL_TR | /* always set ranging bit !!! */
		(config->dataRate << TX_FCTRL_TXBR_SHFT);
		//Transmit Frame Control
		dw1000Hal_writeRegister(TX_FCTRL_ID, (uint8_t *) &dw1000local.txFCTRL,
				TX_FCTRL_LEN - 1); // Just first 4 byte
	}

	if (use_otpconfigvalues & DWT_LOADXTALTRIM) {
		//This is used adjust the crystal frequency
		uint8_t write_buf;

		//DECA: dwt_readfromdevice(FS_CTRL_ID,FS_XTALT_OFFSET,1,&write_buf);
		dw1000Hal_readSubRegister(FS_CTRL_ID, FS_XTALT_OFFSET, &write_buf,
				FS_XTALT_LEN);

		write_buf &= ~FS_XTALT_MASK;

		write_buf |= (FS_XTALT_MASK & dw1000local.xtrim); // we should not change high bits, cause it will cause malfunction

		dw1000Hal_writeSubRegister(FS_CTRL_ID, FS_XTALT_OFFSET, &write_buf,
				FS_XTALT_LEN);
	}

	/* TODO notwendig?
	 if (use_otpconfigvalues & DWT_LOADANTDLY)
	 {
	 //put half of the antenna delay value into tx and half into rx
	 dwt_setrxantennadelay(((dw1000local.antennaDly >> (16*prfIndex)) & 0xFFFF) >> 1);
	 dwt_settxantennadelay(((dw1000local.antennaDly >> (16*prfIndex)) & 0xFFFF) >> 1);
	 }
	 */



	return 0;
}

uint16_t txBufferOffset = 0;

// sends a frame and blocks until finished
int dw1000_sendFrame(uint8_t *payload, uint16_t len) {

	if ((txBufferOffset + len + 2) > 1024){
		return -1; //FIXME: ERRORCODE
	}

	//Write payload
	dw1000Hal_writeRegister(TX_BUFFER_ID + txBufferOffset, payload, len);


	//Set length and offset
    uint32_t reg32 = dw1000local.txFCTRL | len+2 | (txBufferOffset << 22);
	dw1000Hal_writeSubRegister(TX_FCTRL_ID, 0, (uint8_t *) &reg32,  TX_FCTRL_LEN-1);

	txBufferOffset += len + 2;

	txBufferOffset = 0; //FIXME: Löschen, wenn anständige Offsetbehandlung.


//	/* WITHOUT THE NEXT PART: SECOND TIME NO SENDING POSSIBLE, BUT CAN'T BE FOUND IN ORIGINAL DRIVER */
//	uint32_t sys_ctrl = 0;
//	dw1000Hal_readRegister(SYS_CTRL_ID, (uint8_t *)&sys_ctrl, 4);
//	//trace_printf("sys_ctrl: %x\n", sys_ctrl);
//	sys_ctrl |= SYS_CTRL_TRXOFF;//  Immediately cancel all RX and TX operations, bring radio to IDLE state
////	trace_printf("sys_ctrl: %x\n", sys_ctrl);
//	dw1000Hal_writeRegister(SYS_CTRL_ID, (uint8_t *)&sys_ctrl, 4);
//	sys_ctrl = 0;
dw1000Util_forceTrxOff();

    uint8_t temp = (uint8_t) SYS_CTRL_TXSTRT;
    dw1000Hal_writeRegister(SYS_CTRL_ID, (uint8_t *)&temp,1);



void dw1000_extiCallback(void) {
	dw1000Isr_handleInterrupt();
}

int dw_1000_receiveFrameFromIsr(uint8_t * buffer, uint32_t length) {
	dw1000Hal_readRegisterFromIsr(RX_BUFFER_ID, buffer, length); //FromIsr important!
	return 0;
}

int dw1000_setPanAddr(uint16_t addr) {
	return dw1000Hal_writeSubRegister(PANADR_ID, PANADR_SHORT_ADDR_OFFSET,
			(uint8_t*) &addr, PANADR_SHORT_ADDR_LEN);
int dw1000_setPanId(uint16_t addr) {
	return dw1000Hal_writeSubRegister(PANADR_ID, PANADR_PAN_ID_OFFSET,
			(uint8_t*) &addr, PANADR_PAN_ID_LEN);