portapack-mayhem/firmware/application/rffc507x.hpp

836 lines
18 KiB
C++
Raw Normal View History

2015-07-08 11:39:24 -04:00
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* 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.
*/
#ifndef __RFFC507X_H__
#define __RFFC507X_H__
#include "rffc507x_spi.hpp"
#include <cstdint>
#include <array>
#include "dirty_registers.hpp"
#include "rf_path.hpp"
namespace rffc507x {
using reg_t = spi::reg_t;
using address_t = spi::address_t;
constexpr size_t reg_count = 31;
enum class Register : address_t {
LF = 0x00,
XO = 0x01,
CAL_TIME = 0x02,
VCO_CTRL = 0x03,
CT_CAL1 = 0x04,
CT_CAL2 = 0x05,
PLL_CAL1 = 0x06,
PLL_CAL2 = 0x07,
VCO_AUTO = 0x08,
PLL_CTRL = 0x09,
PLL_BIAS = 0x0a,
MIX_CONT = 0x0b,
P1_FREQ1 = 0x0c,
P1_FREQ2 = 0x0d,
P1_FREQ3 = 0x0e,
P2_FREQ1 = 0x0f,
P2_FREQ2 = 0x10,
P2_FREQ3 = 0x11,
FN_CTRL = 0x12,
EXT_MOD = 0x13,
FMOD = 0x14,
SDI_CTRL = 0x15,
GPO = 0x16,
T_VCO = 0x17,
IQMOD1 = 0x18,
IQMOD2 = 0x19,
IQMOD3 = 0x1a,
IQMOD4 = 0x1b,
T_CTRL = 0x1c,
DEV_CTRL = 0x1d,
TEST = 0x1e,
READBACK = 0x1f,
};
enum class Readback : uint8_t {
DeviceID = 0b0000,
TuningCalibration = 0b0001,
TuningVoltage = 0b0010,
StateMachine = 0b0011,
VCOCountL = 0b0100,
VCOCountH = 0b0101,
DCOffsetCal = 0b0110,
VCOMode = 0b0111,
};
struct LF_Type {
reg_t pllcpl : 3;
reg_t p1cpdef : 6;
reg_t p2cpdef : 6;
reg_t lfact : 1;
};
static_assert(sizeof(LF_Type) == sizeof(reg_t), "LF_Type type wrong size");
struct XO_Type {
reg_t suwait : 10;
reg_t xocf : 1;
reg_t xoc : 4;
reg_t xoch : 1;
};
static_assert(sizeof(XO_Type) == sizeof(reg_t), "XO_Type type wrong size");
struct CAL_TIME_Type {
reg_t tkv2 : 4;
reg_t tkv1 : 4;
reg_t reserved0 : 2;
reg_t tct : 5;
reg_t wait : 1;
};
static_assert(sizeof(CAL_TIME_Type) == sizeof(reg_t), "CAL_TIME_Type type wrong size");
struct VCO_CTRL_Type {
reg_t reserved0 : 1;
reg_t icpup : 2;
reg_t refst : 1;
reg_t xoi3 : 1;
reg_t xoi2 : 1;
reg_t xoi1 : 1;
reg_t kvpol : 1;
reg_t kvrng : 1;
reg_t kvavg : 2;
reg_t clkpl : 1;
reg_t ctpol : 1;
reg_t ctavg : 2;
reg_t xtvco : 1;
};
static_assert(sizeof(VCO_CTRL_Type) == sizeof(reg_t), "VCO_CTRL_Type type wrong size");
struct CT_CAL1_Type {
reg_t p1ctdef : 7;
reg_t p1ct : 1;
reg_t p1ctv : 5;
reg_t p1ctgain : 3;
};
static_assert(sizeof(CT_CAL1_Type) == sizeof(reg_t), "CT_CAL1_Type type wrong size");
struct CT_CAL2_Type {
reg_t p2ctdef : 7;
reg_t p2ct : 1;
reg_t p2ctv : 5;
reg_t p2ctgain : 3;
};
static_assert(sizeof(CT_CAL2_Type) == sizeof(reg_t), "CT_CAL2_Type type wrong size");
struct PLL_CAL1_Type {
reg_t reserved0 : 2;
reg_t p1sgn : 1;
reg_t p1kvgain : 3;
reg_t p1dn : 9;
reg_t p1kv : 1;
};
static_assert(sizeof(PLL_CAL1_Type) == sizeof(reg_t), "PLL_CAL1_Type type wrong size");
struct PLL_CAL2_Type {
reg_t reserved0 : 2;
reg_t p2sgn : 1;
reg_t p2kvgain : 3;
reg_t p2dn : 9;
reg_t p2kv : 1;
};
static_assert(sizeof(PLL_CAL2_Type) == sizeof(reg_t), "PLL_CAL2_Type type wrong size");
struct VCO_AUTO_Type {
reg_t reserved0 : 1;
reg_t ctmin : 7;
reg_t ctmax : 7;
reg_t auto_ : 1;
};
static_assert(sizeof(VCO_AUTO_Type) == sizeof(reg_t), "VCO_AUTO_Type type wrong size");
struct PLL_CTRL_Type {
reg_t plldy : 2;
reg_t aloi : 1;
reg_t relok : 1;
reg_t ldlev : 1;
reg_t lden : 1;
reg_t tvco : 5;
reg_t pllst : 1;
reg_t clkdiv : 3;
reg_t divby : 1;
};
static_assert(sizeof(PLL_CTRL_Type) == sizeof(reg_t), "PLL_CTRL_Type type wrong size");
struct PLL_BIAS_Type {
reg_t p2vcoi : 3;
reg_t p2loi : 4;
reg_t reserved0 : 1;
reg_t p1vcoi : 3;
reg_t p1loi : 4;
reg_t reserved1 : 1;
};
static_assert(sizeof(PLL_BIAS_Type) == sizeof(reg_t), "PLL_BIAS_Type type wrong size");
struct MIX_CONT_Type {
reg_t reserved0 : 9;
reg_t p2mixidd : 3;
reg_t p1mixidd : 3;
reg_t fulld : 1;
};
static_assert(sizeof(MIX_CONT_Type) == sizeof(reg_t), "MIX_CONT_Type type wrong size");
struct P1_FREQ1_Type {
reg_t p1vcosel : 2;
reg_t p1presc : 2;
reg_t p1lodiv : 3;
reg_t p1n : 9;
};
static_assert(sizeof(P1_FREQ1_Type) == sizeof(reg_t), "P1_FREQ1_Type type wrong size");
struct P1_FREQ2_Type {
reg_t p1nmsb : 16;
};
static_assert(sizeof(P1_FREQ2_Type) == sizeof(reg_t), "P1_FREQ2_Type type wrong size");
struct P1_FREQ3_Type {
reg_t reserved0 : 8;
reg_t p1nlsb : 8;
};
static_assert(sizeof(P1_FREQ3_Type) == sizeof(reg_t), "P1_FREQ3_Type type wrong size");
struct P2_FREQ1_Type {
reg_t p2vcosel : 2;
reg_t p2presc : 2;
reg_t p2lodiv : 3;
reg_t p2n : 9;
};
static_assert(sizeof(P2_FREQ1_Type) == sizeof(reg_t), "P2_FREQ1_Type type wrong size");
struct P2_FREQ2_Type {
reg_t p2nmsb : 16;
};
static_assert(sizeof(P2_FREQ2_Type) == sizeof(reg_t), "P2_FREQ2_Type type wrong size");
struct P2_FREQ3_Type {
reg_t reserved0 : 8;
reg_t p2nlsb : 8;
};
static_assert(sizeof(P2_FREQ3_Type) == sizeof(reg_t), "P2_FREQ3_Type type wrong size");
struct FN_CTRL_Type {
reg_t reserved0 : 1;
reg_t tzps : 1;
reg_t dmode : 1;
reg_t fm : 1;
reg_t dith : 1;
reg_t mode : 1;
reg_t phsalndly : 2;
reg_t phsalngain : 3;
reg_t phaln : 1;
reg_t sdm : 2;
reg_t dithr : 1;
reg_t fnz : 1;
};
static_assert(sizeof(FN_CTRL_Type) == sizeof(reg_t), "FN_CTRL_Type type wrong size");
struct EXT_MOD_Type {
reg_t reserved0 : 10;
reg_t modstep : 4;
reg_t modsetup : 2;
};
static_assert(sizeof(EXT_MOD_Type) == sizeof(reg_t), "EXT_MOD_Type type wrong size");
struct FMOD_Type {
reg_t modulation : 16;
};
static_assert(sizeof(FMOD_Type) == sizeof(reg_t), "FMOD_Type type wrong size");
struct SDI_CTRL_Type {
reg_t reserved0 : 1;
reg_t reset : 1;
reg_t reserved1 : 9;
reg_t addr : 1;
reg_t fourwire : 1;
reg_t mode : 1;
reg_t enbl : 1;
reg_t sipin : 1;
};
static_assert(sizeof(SDI_CTRL_Type) == sizeof(reg_t), "SDI_CTRL_Type type wrong size");
struct GPO_Type {
reg_t lock : 1;
reg_t gate : 1;
reg_t p1gpo : 7;
reg_t p2gpo : 7;
};
static_assert(sizeof(GPO_Type) == sizeof(reg_t), "GPO_Type type wrong size");
struct T_VCO_Type {
reg_t reserved0 : 7;
reg_t curve_vco3 : 3;
reg_t curve_vco2 : 3;
reg_t curve_vco1 : 3;
};
static_assert(sizeof(T_VCO_Type) == sizeof(reg_t), "T_VCO_Type type wrong size");
struct IQMOD1_Type {
reg_t bufdc : 2;
reg_t divbias : 1;
reg_t calblk : 1;
reg_t calnul : 1;
reg_t calon : 1;
reg_t lobias : 2;
reg_t modbias : 3;
/* Also defined as ctrl : 5 */
reg_t modiv : 1;
reg_t mod : 1;
reg_t txlo : 1;
reg_t bbgm : 1;
reg_t ctrl : 1;
};
static_assert(sizeof(IQMOD1_Type) == sizeof(reg_t), "IQMOD1_Type type wrong size");
struct IQMOD2_Type {
reg_t modbuf : 2;
reg_t mod : 2;
reg_t calatten : 2;
reg_t rctune : 6;
reg_t bbatten : 4;
};
static_assert(sizeof(IQMOD2_Type) == sizeof(reg_t), "IQMOD2_Type type wrong size");
struct IQMOD3_Type {
/* Documentation error */
reg_t reserved0 : 3;
reg_t dacen : 1;
reg_t bufdacq : 6;
reg_t bufdaci : 6;
};
static_assert(sizeof(IQMOD3_Type) == sizeof(reg_t), "IQMOD3_Type type wrong size");
struct IQMOD4_Type {
/* Documentation error */
reg_t bufbias2 : 2;
reg_t bufbias1 : 2;
reg_t moddacq : 6;
reg_t moddaci : 6;
};
static_assert(sizeof(IQMOD4_Type) == sizeof(reg_t), "IQMOD4_Type type wrong size");
struct T_CTRL_Type {
reg_t reserved0 : 5;
reg_t v_test : 1;
reg_t ldo_by : 1;
reg_t ext_filt : 1;
reg_t ref_sel : 1;
reg_t filt_ctrl : 2;
reg_t fc_en : 1;
reg_t tbl_sel : 2;
reg_t tc_en : 2;
};
static_assert(sizeof(T_CTRL_Type) == sizeof(reg_t), "T_CTRL_Type type wrong size");
struct DEV_CTRL_Type {
reg_t reserved0 : 1;
reg_t bypas : 1;
reg_t ctclk : 1;
reg_t dac : 1;
reg_t cpd : 1;
reg_t cpu : 1;
reg_t rsmstopst : 5;
reg_t rsmst : 1;
reg_t readsel : 4;
};
static_assert(sizeof(DEV_CTRL_Type) == sizeof(reg_t), "DEV_CTRL_Type type wrong size");
struct TEST_Type {
reg_t lfsrd : 1;
reg_t rcbyp : 1;
reg_t rgbyp : 1;
reg_t lfsrt : 1;
reg_t lfsrgatetime : 4;
reg_t lfsrp : 1;
reg_t lfsr : 1;
reg_t tsel : 2;
reg_t tmux : 3;
reg_t ten : 1;
};
static_assert(sizeof(TEST_Type) == sizeof(reg_t), "TEST_Type type wrong size");
struct READBACK_0000_Type {
reg_t mrev_id : 3;
reg_t dev_id : 13;
};
static_assert(sizeof(READBACK_0000_Type) == sizeof(reg_t), "READBACK_0000_Type type wrong size");
struct READBACK_0001_Type {
reg_t reserved0 : 1;
reg_t ctfail : 1;
reg_t cp_cal : 6;
reg_t ct_cal : 7;
reg_t lock : 1;
};
static_assert(sizeof(READBACK_0001_Type) == sizeof(reg_t), "READBACK_0001_Type type wrong size");
struct READBACK_0010_Type {
reg_t v1_cal : 8;
reg_t v0_cal : 8;
};
static_assert(sizeof(READBACK_0010_Type) == sizeof(reg_t), "READBACK_0010_Type type wrong size");
struct READBACK_0011_Type {
reg_t reserved0 : 9;
reg_t f_errflag : 2;
reg_t rsm_state : 5;
};
static_assert(sizeof(READBACK_0011_Type) == sizeof(reg_t), "READBACK_0011_Type type wrong size");
struct READBACK_0100_Type {
reg_t vco_count_l : 16;
};
static_assert(sizeof(READBACK_0100_Type) == sizeof(reg_t), "READBACK_0100_Type type wrong size");
struct READBACK_0101_Type {
reg_t vco_count_h : 16;
};
static_assert(sizeof(READBACK_0101_Type) == sizeof(reg_t), "READBACK_0101_Type type wrong size");
struct READBACK_0110_Type {
reg_t reserved0 : 14;
reg_t cal_fbq : 1;
reg_t cal_fbi : 1;
};
static_assert(sizeof(READBACK_0110_Type) == sizeof(reg_t), "READBACK_0110_Type type wrong size");
struct READBACK_0111_Type {
reg_t reserved0 : 11;
reg_t vco_tc_curve : 3;
reg_t vco_sel : 2;
};
static_assert(sizeof(READBACK_0111_Type) == sizeof(reg_t), "READBACK_0111_Type type wrong size");
struct Register_Type {
LF_Type lf;
XO_Type xo;
CAL_TIME_Type cal_time;
VCO_CTRL_Type vco_ctrl;
CT_CAL1_Type ct_cal1;
CT_CAL2_Type ct_cal2;
PLL_CAL1_Type pll_cal1;
PLL_CAL2_Type pll_cal2;
VCO_AUTO_Type vco_auto;
PLL_CTRL_Type pll_ctrl;
PLL_BIAS_Type pll_bias;
MIX_CONT_Type mix_cont;
P1_FREQ1_Type p1_freq1;
P1_FREQ2_Type p1_freq2;
P1_FREQ3_Type p1_freq3;
P2_FREQ1_Type p2_freq1;
P2_FREQ2_Type p2_freq2;
P2_FREQ3_Type p2_freq3;
FN_CTRL_Type fn_ctrl;
EXT_MOD_Type ext_mod;
FMOD_Type fmod;
SDI_CTRL_Type sdi_ctrl;
GPO_Type gpo;
T_VCO_Type t_vco;
IQMOD1_Type iqmod1;
IQMOD2_Type iqmod2;
IQMOD3_Type iqmod3;
IQMOD4_Type iqmod4;
T_CTRL_Type t_ctrl;
DEV_CTRL_Type dev_ctrl;
TEST_Type test;
};
static_assert(sizeof(Register_Type) == reg_count * sizeof(reg_t), "Register_Type wrong size");
struct RegisterMap {
constexpr RegisterMap(
Register_Type values
) : r(values)
{
}
union {
Register_Type r;
std::array<reg_t, reg_count> w;
};
};
static_assert(sizeof(RegisterMap) == reg_count * sizeof(reg_t), "RegisterMap type wrong size");
#if 0
struct ReadbackType {
union {
READBACK_0000_Type readback_0000;
READBACK_0001_Type readback_0001;
READBACK_0010_Type readback_0010;
READBACK_0011_Type readback_0011;
READBACK_0100_Type readback_0100;
READBACK_0101_Type readback_0101;
READBACK_0110_Type readback_0110;
READBACK_0111_Type readback_0111;
reg_t w;
};
};
#endif
#if 0
/* Revision 1 devices (mrev_id = 001):
* RFFC2071/2072/5071/5072, RFMD2080/2081
*/
constexpr RegisterMap default_revision_1 { std::array<reg_t, reg_count> {
0xbefa, 0x4064, 0x9055, 0x2d02,
0xb0bf, 0xb0bf, 0x0028, 0x0028,
0xfc06, 0x8220, 0x0202, 0x4800,
0x2324, 0x6276, 0x2700, 0x2f16,
0x3b13, 0xb100, 0x2a80, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0283, 0xf00f, 0x0000, 0x000f,
0x0000, 0x1000, 0x0001,
} };
/* Revision 2 devices (mrev_id = 010):
* RFFC2071A/2072A/5071A/5072A
*/
constexpr RegisterMap default_revision_2 { std::array<reg_t, reg_count> {
0xbefa, 0x4064, 0x9055, 0x2d02,
0xacbf, 0xacbf, 0x0028, 0x0028,
0xff00, 0x8220, 0x0202, 0x4800,
0x1a94, 0xd89d, 0x8900, 0x1e84,
0x89d8, 0x9d00, 0x2a80, 0x0000,
0x0000, 0x0000, 0x0000, 0x4900,
0x0281, 0xf00f, 0x0000, 0x0005,
0xc840, 0x1000, 0x0005,
} };
#endif
constexpr RegisterMap default_hackrf_one { Register_Type {
/* Started with recommended defaults for revision 1 devices
* (mrev_id = 001), RFFC2071/2072/5071/5072, RFMD2080/2081.
* Modified according to mixer programming guide.
*/
.lf = { /* 0 */
.pllcpl = 0b010,
.p1cpdef = 0b011111,
.p2cpdef = 0b011111,
.lfact = 1,
},
.xo = { /* 1 */
.suwait = 0b0001100100,
.xocf = 0b0,
.xoc = 0b1000,
.xoch = 0b0,
},
.cal_time = { /* 2 */
.tkv2 = 0b0101,
.tkv1 = 0b0101,
.reserved0 = 0b00,
.tct = 0b00100,
.wait = 0b1,
},
.vco_ctrl = { /* 3 */
.reserved0 = 0b0,
.icpup = 0b01,
.refst = 0b0,
.xoi3 = 0b0,
.xoi2 = 0b0,
.xoi1 = 0b0,
.kvpol = 0b0,
.kvrng = 0b1,
.kvavg = 0b10,
.clkpl = 0b1,
.ctpol = 0b0,
.ctavg = 0b01,
.xtvco = 0b0,
},
.ct_cal1 = { /* 4 */
.p1ctdef = 0b0111111,
.p1ct = 0b1,
.p1ctv = 12, /* RFMD recommneded change: 16 -> 12 */
.p1ctgain = 0b101,
},
.ct_cal2 = { /* 5 */
.p2ctdef = 0b0111111,
.p2ct = 0b1,
.p2ctv = 12, /* RFMD recommneded change: 16 -> 12 */
.p2ctgain = 0b101,
},
.pll_cal1 = { /* 6 */
.reserved0 = 0b00,
.p1sgn = 0b0,
.p1kvgain = 0b101,
.p1dn = 0b000000000,
.p1kv = 0b0,
},
.pll_cal2 = { /* 7 */
.reserved0 = 0b00,
.p2sgn = 0b0,
.p2kvgain = 0b101,
.p2dn = 0b000000000,
.p2kv = 0b0,
},
.vco_auto = { /* 8 */
.reserved0 = 0b0,
.ctmin = 0, /* RFMD recommended change: 3 -> 0 */
.ctmax = 127, /* RFMD recommended change: 124 -> 127 */
.auto_ = 0b1,
},
.pll_ctrl = { /* 9 */
.plldy = 0b00,
.aloi = 0b0,
.relok = 0b0,
.ldlev = 0b0,
.lden = 0b1,
.tvco = 0b01000,
.pllst = 0b0,
.clkdiv = 0b000,
.divby = 0b1,
},
.pll_bias = { /* 10 */
.p2vcoi = 0b010,
.p2loi = 0b0000,
.reserved0 = 0b0,
.p1vcoi = 0b010,
.p1loi = 0b0000,
.reserved1 = 0b0,
},
.mix_cont = { /* 11 */
.reserved0 = 0b000000000,
.p2mixidd = 4,
.p1mixidd = 4,
.fulld = 0b0, /* Part on HackRF is half-duplex (single mixer) */
},
.p1_freq1 = { /* 12 */
.p1vcosel = 0b00, /* RFMD VCO bank 1 configuration from A series part */
.p1presc = 0b01,
.p1lodiv = 0b001,
.p1n = 0b000110101,
},
.p1_freq2 = { /* 13 */
.p1nmsb = 0xd89d, /* RFMD VCO bank 1 configuration from A series part */
},
.p1_freq3 = { /* 14 */
.reserved0 = 0b00000000, /* RFMD VCO bank 1 configuration from A series part */
.p1nlsb = 0x89,
},
.p2_freq1 = { /* 15 */
.p2vcosel = 0b00, /* RFMD VCO bank 2 configuration from A series part */
.p2presc = 0b01,
.p2lodiv = 0b000,
.p2n = 0b000111101,
},
.p2_freq2 = { /* 16 */
.p2nmsb = 0x89d8, /* RFMD VCO bank 2 configuration from A series part */
},
.p2_freq3 = { /* 17 */
.reserved0 = 0b00000000, /* RFMD VCO bank 2 configuration from A series part */
.p2nlsb = 0x9d,
},
.fn_ctrl = { /* 18 */
.reserved0 = 0b0,
.tzps = 0b0,
.dmode = 0b0,
.fm = 0b0,
.dith = 0b0,
.mode = 0b0,
.phsalndly = 0b10,
.phsalngain = 0b010,
.phaln = 0b1,
.sdm = 0b10,
.dithr = 0b0,
.fnz = 0b0,
},
.ext_mod = { /* 19 */
.reserved0 = 0b0000000000,
.modstep = 0b0000,
.modsetup = 0b00,
},
.fmod = { /* 20 */
.modulation = 0x0000,
},
.sdi_ctrl = { /* 21 */
.reserved0 = 0b0,
.reset = 0b0,
.reserved1 = 0b000000000,
.addr = 0b0,
.fourwire = 0b0, /* Use three pin SPI mode */
.mode = 0b1, /* Active PLL register bank 2, active mixer 2 */
.enbl = 0b0, /* Part is initially disabled */
.sipin = 0b1, /* Control MODE, ENBL from SPI bus */
},
.gpo = { /* 22 */
.lock = 0b1, /* Present LOCK signal on GPIO4/LD/DO, HackRF One test point P6 */
.gate = 0b1, /* GPOs active even when part is disabled (ENBL=0) */
.p1gpo = 0b0000001, /* Turn on GPO1 to turn *off* !ANT_BIAS (GPO numbering is one-based) */
.p2gpo = 0b0000001, /* Turn on GPO1 to turn *off* !ANT_BIAS (GPO numbering is one-based) */
},
.t_vco = { /* 23 */
.reserved0 = 0b0000000,
.curve_vco3 = 0b000,
.curve_vco2 = 0b000,
.curve_vco1 = 0b000,
},
.iqmod1 = { /* 24 */
.bufdc = 0b11,
.divbias = 0b0,
.calblk = 0b0,
.calnul = 0b0,
.calon = 0b0,
.lobias = 0b10,
.modbias = 0b010,
.modiv = 0b0,
.mod = 0b0,
.txlo = 0b0,
.bbgm = 0b0,
.ctrl = 0b0,
},
.iqmod2 = { /* 25 */
.modbuf = 0b11,
.mod = 0b11,
.calatten = 0b00,
.rctune = 0b000000,
.bbatten = 0b1111,
},
.iqmod3 = { /* 26 */
.reserved0 = 0b000,
.dacen = 0b0,
.bufdacq = 0b000000,
.bufdaci = 0b000000,
},
.iqmod4 = { /* 27 */
.bufbias2 = 0b11,
.bufbias1 = 0b11,
.moddacq = 0b000000,
.moddaci = 0b000000,
},
.t_ctrl = { /* 28 */
.reserved0 = 0b00000,
.v_test = 0b0,
.ldo_by = 0b0,
.ext_filt = 0b0,
.ref_sel = 0b0,
.filt_ctrl = 0b00,
.fc_en = 0b0,
.tbl_sel = 0b00,
.tc_en = 0b00,
},
.dev_ctrl = { /* 29 */
.reserved0 = 0b0,
.bypas = 0b0,
.ctclk = 0b0,
.dac = 0b0,
.cpd = 0b0,
.cpu = 0b0,
.rsmstopst = 0b00000,
.rsmst = 0b0,
.readsel = 0b0001,
},
.test = { /* 30 */
.lfsrd = 0b1,
.rcbyp = 0b0,
.rgbyp = 0b1, /* RFMD recommended change: 0 -> 1 */
.lfsrt = 0b0,
.lfsrgatetime = 0b0000,
.lfsrp = 0b0,
.lfsr = 0b0,
.tsel = 0b00,
.tmux = 0b000,
.ten = 0b0,
},
} };
class RFFC507x {
public:
void init();
void reset();
void flush();
void enable();
void disable();
void set_mixer_current(const uint8_t value);
void set_frequency(const rf::Frequency lo_frequency);
RegisterMap registers();
private:
spi::SPI _bus;
RegisterMap _map { default_hackrf_one };
DirtyRegisters<Register, reg_count> _dirty;
void write(const address_t reg_num, const reg_t value);
reg_t read(const address_t reg_num);
void write(const Register reg, const reg_t value);
reg_t read(const Register reg);
void flush_one(const Register reg);
reg_t readback(const Readback readback);
void init_for_best_performance();
};
} /* rffc507x */
#endif/*__RFFC507X_H__*/