diff --git a/firmware/common/rffc5071.c b/firmware/common/rffc5071.c new file mode 100644 index 00000000..f9492044 --- /dev/null +++ b/firmware/common/rffc5071.c @@ -0,0 +1,193 @@ +/* + * Copyright 2012 Michael Ossmann + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include "hackrf_core.h" +#include "rffc5071.h" + +/* Set up pins for bit-banged serial interface. */ +void rffc5071_init(void) +{ + /* Configure GPIO pins. */ + scu_pinmux(SCU_MIXER_ENX, SCU_GPIO_FAST); + scu_pinmux(SCU_MIXER_CLK, SCU_GPIO_FAST); + scu_pinmux(SCU_MIXER_DATA, SCU_GPIO_FAST); + + /* Set GPIO pins as outputs. */ + GPIO3_DIR |= (PIN_MIXER_ENX | PIN_MIXER_CLK | PIN_MIXER_DATA); + + /* set to known state */ + gpio_set(PORT_MIXER, PIN_MIXER_ENX); /* active low */ + gpio_clear(PORT_MIXER, (PIN_MIXER_CLK | PIN_MIXER_DATA)); + + //FIXME hard coded setup, fields not broken out + /* initial setup */ + rffc5071_reg_write(RFFC5071_P2_FREQ1, 0x0000); + rffc5071_reg_write(RFFC5071_VCO_AUTO, 0xff00); + rffc5071_reg_write(RFFC5071_CT_CAL1, 0xacbf); + rffc5071_reg_write(RFFC5071_CT_CAL2, 0xacbf); + rffc5071_reg_write(RFFC5071_TEST, 0x0005); + + /* set to be configured via 3-wire interface, not control pins */ + rffc5071_reg_write(RFFC5071_SDI_CTRL, 0x8000); + + //rffc5071_reg_write(MIX_CONT, 0xc800); /* full duplex */ + rffc5071_reg_write(RFFC5071_MIX_CONT, 0x4800); /* half duplex */ + + /* + * setup for 2 GHz LO: + * n_lo = 1 + * lodiv = 2 + * fvco = 4 GHz + * fbkdiv = 4 + * ndiv = 20 + * n = 20 + * nummsb = 0 + * numlsb = 0 + */ + rffc5071_reg_write(RFFC5071_P1_FREQ1, 0x0a28); + rffc5071_reg_write(RFFC5071_P1_FREQ2, 0x0000); + rffc5071_reg_write(RFFC5071_P1_FREQ3, 0x0000); + /* charge pump set for VCO > 3.2 GHz */ + rffc5071_reg_write(RFFC5071_LF, 0xBEFB); + + /* enable device */ + rffc5071_reg_write(RFFC5071_SDI_CTRL, 0xc000); /* mixer 1 (TX) */ + //rffc5071_reg_write(RFFC5071_SDI_CTRL, 0xe000); /* mixer 2 (RX) */ +} + +void serial_delay(void) +{ + uint32_t i; + + for (i = 0; i < 1000; i++) + __asm__("nop"); +} + +/* + * Send 25 bits: + * first bit is ignored, + * second bit is zero for write operation, + * next 7 bits are register address, + * next 16 bits are register value. + */ +void rffc5071_reg_write(uint8_t reg, uint16_t val) +{ + int bits = 25; + int msb = 1 << (bits -1); + uint32_t data = ((reg & 0x7f) << 16) | val; + + /* make sure everything is starting in the correct state */ + gpio_set(PORT_MIXER, PIN_MIXER_ENX); + gpio_clear(PORT_MIXER, (PIN_MIXER_CLK | PIN_MIXER_DATA)); + serial_delay(); + + /* start transaction by bringing ENX low */ + gpio_clear(PORT_MIXER, PIN_MIXER_ENX); + serial_delay(); + + while (bits--) { + if (data & msb) + gpio_set(PORT_MIXER, PIN_MIXER_DATA); + else + gpio_clear(PORT_MIXER, PIN_MIXER_DATA); + data <<= 1; + + serial_delay(); + gpio_set(PORT_MIXER, PIN_MIXER_CLK); + + serial_delay(); + gpio_clear(PORT_MIXER, PIN_MIXER_CLK); + } + + serial_delay(); + gpio_set(PORT_MIXER, PIN_MIXER_ENX); +} + +/* + * Send 9 bits: + * first bit is ignored, + * second bit is one for read operation, + * next 7 bits are register address. + * Then receive 16 bits (register value). + */ +uint16_t rffc5071_reg_read(uint8_t reg) +{ + int bits = 9; + int msb = 1 << (bits -1); + uint32_t data = 0x80 | (reg & 0x7f); + + /* make sure everything is starting in the correct state */ + gpio_set(PORT_MIXER, PIN_MIXER_ENX); + gpio_clear(PORT_MIXER, (PIN_MIXER_CLK | PIN_MIXER_DATA)); + serial_delay(); + + /* start transaction by bringing ENX low */ + gpio_clear(PORT_MIXER, PIN_MIXER_ENX); + serial_delay(); + + while (bits--) { + if (data & msb) + gpio_set(PORT_MIXER, PIN_MIXER_DATA); + else + gpio_clear(PORT_MIXER, PIN_MIXER_DATA); + data <<= 1; + + serial_delay(); + gpio_set(PORT_MIXER, PIN_MIXER_CLK); + + serial_delay(); + gpio_clear(PORT_MIXER, PIN_MIXER_CLK); + } + + serial_delay(); + gpio_set(PORT_MIXER, PIN_MIXER_CLK); + + serial_delay(); + gpio_clear(PORT_MIXER, PIN_MIXER_CLK); + + bits = 16; + data = 0; + /* set DATA line as input */ + GPIO3_DIR &= ~PIN_MIXER_DATA; + + while (bits--) { + data <<= 1; + + serial_delay(); + gpio_set(PORT_MIXER, PIN_MIXER_CLK); + + serial_delay(); + gpio_clear(PORT_MIXER, PIN_MIXER_CLK); + if (MIXER_DATA_STATE) + data |= 1; + } + /* set DATA line as output */ + GPIO3_DIR |= PIN_MIXER_DATA; + + serial_delay(); + gpio_set(PORT_MIXER, PIN_MIXER_ENX); + + return data; +} diff --git a/firmware/common/rffc5071.h b/firmware/common/rffc5071.h new file mode 100644 index 00000000..92a14888 --- /dev/null +++ b/firmware/common/rffc5071.h @@ -0,0 +1,60 @@ +/* + * Copyright 2012 Michael Ossmann + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include + +/* register names */ +#define RFFC5071_LF 0x00 +#define RFFC5071_XO 0x01 +#define RFFC5071_CAL_TIME 0x02 +#define RFFC5071_VCO_CTRL 0x03 +#define RFFC5071_CT_CAL1 0x04 +#define RFFC5071_CT_CAL2 0x05 +#define RFFC5071_PLL_CAL1 0x06 +#define RFFC5071_PLL_CAL2 0x07 +#define RFFC5071_VCO_AUTO 0x08 +#define RFFC5071_PLL_CTRL 0x09 +#define RFFC5071_PLL_BIAS 0x0A +#define RFFC5071_MIX_CONT 0x0B +#define RFFC5071_P1_FREQ1 0x0C +#define RFFC5071_P1_FREQ2 0x0D +#define RFFC5071_P1_FREQ3 0x0E +#define RFFC5071_P2_FREQ1 0x0F +#define RFFC5071_P2_FREQ2 0x10 +#define RFFC5071_P2_FREQ3 0x11 +#define RFFC5071_FN_CTRL 0x12 +#define RFFC5071_EXT_MOD 0x13 +#define RFFC5071_FMOD 0x14 +#define RFFC5071_SDI_CTRL 0x15 +#define RFFC5071_GPO 0x16 +#define RFFC5071_T_VCO 0x17 +#define RFFC5071_IQMOD1 0x18 +#define RFFC5071_IQMOD2 0x19 +#define RFFC5071_IQMOD3 0x1A +#define RFFC5071_IQMOD4 0x1B +#define RFFC5071_T_CTRL 0x1C +#define RFFC5071_DEV_CTRL 0x1D +#define RFFC5071_TEST 0x1E +#define RFFC5071_READBACK 0x1F + +void rffc5071_init(void); +void rffc5071_reg_write(uint8_t reg, uint16_t val); +uint16_t rffc5071_reg_read(uint8_t reg);