/* * 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 __MAX2837_H__ #define __MAX2837_H__ #include "gpio.hpp" #include "spi_arbiter.hpp" #include #include #include "dirty_registers.hpp" #include "rf_path.hpp" #include "utility.hpp" namespace max2837 { enum class Mode { Mask_Enable = 0b001, Mask_RxEnable = 0b010, Mask_TxEnable = 0b100, Shutdown = 0b000, Standby = Mask_Enable, Receive = Mask_Enable | Mask_RxEnable, Transmit = Mask_Enable | Mask_TxEnable, }; /*************************************************************************/ namespace lo { constexpr std::array band { { { .min = 2300000000, .max = 2400000000, }, { .min = 2400000000, .max = 2500000000, }, { .min = 2500000000, .max = 2600000000, }, { .min = 2600000000, .max = 2700000000, }, } }; } /* namespace lo */ /*************************************************************************/ namespace lna { constexpr int8_t gain_db_min = 0; constexpr int8_t gain_db_max = 40; constexpr int8_t gain_db_step = 8; constexpr std::array band { { { .min = 2300000000, .max = 2500000000, }, { .min = 2500000000, .max = 2700000000, }, } }; } /* namespace lna */ /*************************************************************************/ namespace vga { constexpr int8_t gain_db_min = 0; constexpr int8_t gain_db_max = 62; constexpr int8_t gain_db_step = 2; } /* namespace vga */ /*************************************************************************/ namespace filter { constexpr std::array bandwidths { /* Assumption: these values are in ascending order */ 1750000, 2500000, /* Some documentation says 2.25MHz */ 3500000, 5000000, 5500000, 6000000, 7000000, 8000000, 9000000, 10000000, 12000000, 14000000, 15000000, 20000000, 24000000, 28000000, }; constexpr auto bandwidth_minimum = bandwidths[0]; constexpr auto bandwidth_maximum = bandwidths[bandwidths.size() - 1]; } /* namespace filter */ /*************************************************************************/ using reg_t = uint16_t; using address_t = uint8_t; constexpr size_t reg_count = 32; enum class Register : address_t { RXRF_1 = 0, RXRF_2 = 1, LPF_1 = 2, LPF_2 = 3, LPF_3_VGA_1 = 4, VGA_2 = 5, VGA_3_RX_TOP = 6, TEMP_SENSE = 7, RX_TOP_RX_BIAS = 8, RX_TOP = 9, TX_TOP_1 = 10, TX_TOP_2 = 11, HPFSM_1 = 12, HPFSM_2 = 13, HPFSM_3 = 14, HPFSM_4 = 15, SPI_EN = 16, SYN_FR_DIV_1 = 17, SYN_FR_DIV_2 = 18, SYN_INT_DIV = 19, SYN_CFG_1 = 20, SYN_CFG_2 = 21, VAS_CFG = 22, LO_MISC = 23, XTAL_CFG = 24, VCO_CFG = 25, LO_GEN = 26, PA_DRV_PA_DAC = 27, PA_DAC = 28, TX_GAIN = 29, TX_LO_IQ = 30, TX_DC_CORR = 31, }; struct RXRF_1_Type { reg_t LNA_EN : 1; reg_t Mixer_EN : 1; reg_t RxLO_EN : 1; reg_t Lbias : 2; reg_t Mbias : 2; reg_t buf : 2; reg_t LNAband : 1; reg_t RESERVED0 : 6; }; static_assert(sizeof(RXRF_1_Type) == sizeof(reg_t), "RXRF_1_Type wrong size"); struct RXRF_2_Type { reg_t LNAtune : 1; reg_t LNAde_Q : 1; reg_t L : 3; reg_t iqerr_trim : 5; reg_t RESERVED0 : 6; }; static_assert(sizeof(RXRF_2_Type) == sizeof(reg_t), "RXRF_2_Type wrong size"); struct LPF_1_Type { reg_t LPF_EN : 1; reg_t TxBB_EN : 1; reg_t ModeCtrl : 2; reg_t FT : 4; reg_t dF : 2; reg_t RESERVED0 : 6; }; static_assert(sizeof(LPF_1_Type) == sizeof(reg_t), "LPF_1_Type wrong size"); struct LPF_2_Type { reg_t PT_SPI : 4; reg_t Bqd : 3; reg_t TxRPCM : 3; reg_t RESERVED0 : 6; }; static_assert(sizeof(LPF_2_Type) == sizeof(reg_t), "LPF_2_Type wrong size"); struct LPF_3_VGA_1_Type { reg_t RP : 2; reg_t TxBuff : 2; reg_t VGA_EN : 1; reg_t VGAMUX_enable : 1; reg_t BUFF_Curr : 2; reg_t BUFF_VCM : 2; reg_t RESERVED0 : 6; }; static_assert(sizeof(LPF_3_VGA_1_Type) == sizeof(reg_t), "LPF_3_VGA_1_Type wrong size"); struct VGA_2_Type { reg_t VGA : 5; reg_t sel_In1_In2 : 1; reg_t turbo15n20 : 1; reg_t VGA_Curr : 2; reg_t fuse_arm : 1; reg_t RESERVED0 : 6; }; static_assert(sizeof(VGA_2_Type) == sizeof(reg_t), "VGA_2_Type wrong size"); struct VGA_3_RX_TOP_Type { reg_t RESERVED0 : 6; reg_t RSSI_EN_SPIenables : 1; reg_t RSSI_MUX : 1; reg_t RSSI_MODE : 1; reg_t LPF_MODE_SEL : 1; reg_t RESERVED1 : 6; }; static_assert(sizeof(VGA_3_RX_TOP_Type) == sizeof(reg_t), "VGA_3_RX_TOP_Type wrong size"); struct TEMP_SENSE_Type { reg_t ts_adc : 5; reg_t RESERVED0 : 1; reg_t PLL_test_output : 1; reg_t VAS_test_output : 1; reg_t HPFSM_test_output : 1; reg_t LOGEN_trim_divider_test_output : 1; reg_t RESERVED1 : 6; }; static_assert(sizeof(TEMP_SENSE_Type) == sizeof(reg_t), "TEMP_SENSE_Type wrong size"); struct RX_TOP_RX_BIAS_Type { reg_t LNAgain_SPI_EN : 1; reg_t VGAgain_SPI_EN : 1; reg_t EN_Bias_Trim : 1; reg_t BIAS_TRIM_SPI : 5; reg_t BIAS_TRIM_CNTRL : 1; reg_t RX_IQERR_SPI_EN : 1; reg_t RESERVED0 : 6; }; static_assert(sizeof(RX_TOP_RX_BIAS_Type) == sizeof(reg_t), "RX_TOP_RX_BIAS_Type wrong size"); struct RX_TOP_Type { reg_t ts_adc_trigger : 1; reg_t ts_en : 1; reg_t LPFtrim_SPI_EN : 1; reg_t DOUT_DRVH : 1; reg_t DOUT_PU : 1; reg_t DOUT_SEL : 3; reg_t fuse_th : 1; reg_t fuse_burn_gkt : 1; reg_t RESERVED0 : 6; }; static_assert(sizeof(RX_TOP_Type) == sizeof(reg_t), "RX_TOP_Type wrong size"); struct TX_TOP_1_Type { reg_t RESERVED0 : 1; reg_t TXCAL_GAIN : 2; reg_t TXCAL_V2I_FILT : 3; reg_t TX_BIAS_ADJ : 2; reg_t RESERVED1 : 2; reg_t RESERVED2 : 6; }; static_assert(sizeof(TX_TOP_1_Type) == sizeof(reg_t), "TX_TOP_1_Type wrong size"); struct TX_TOP_2_Type { reg_t AMD_SPI_EN : 1; reg_t TXMXR_V2I_GAIN : 4; reg_t RESERVED0 : 5; reg_t RESERVED1 : 6; }; static_assert(sizeof(TX_TOP_2_Type) == sizeof(reg_t), "TX_TOP_2_Type wrong size"); struct HPFSM_1_Type { reg_t HPC_10M : 2; reg_t HPC_10M_GAIN : 2; reg_t HPC_600k : 3; reg_t HPC_600k_GAIN : 3; reg_t RESERVED0 : 6; }; static_assert(sizeof(HPFSM_1_Type) == sizeof(reg_t), "HPFSM_1_Type wrong size"); struct HPFSM_2_Type { reg_t HPC_100k : 2; reg_t HPC_100k_GAIN : 2; reg_t HPC_30k : 2; reg_t HPC_30k_GAIN : 2; reg_t HPC_1k : 2; reg_t RESERVED0 : 6; }; static_assert(sizeof(HPFSM_2_Type) == sizeof(reg_t), "HPFSM_2_Type wrong size"); struct HPFSM_3_Type { reg_t HPC_1k_GAIN : 2; reg_t HPC_DELAY : 2; reg_t HPC_STOP : 2; reg_t HPC_STOP_M2 : 2; reg_t HPC_RXGAIN_EN : 1; reg_t HPC_MODE : 1; reg_t RESERVED0 : 6; }; static_assert(sizeof(HPFSM_3_Type) == sizeof(reg_t), "HPFSM_3_Type wrong size"); struct HPFSM_4_Type { reg_t HPC_DIVH : 1; reg_t HPC_TST : 5; reg_t HPC_SEQ_BYP : 1; reg_t DOUT_CSB_SEL : 1; reg_t RESERVED0 : 2; reg_t RESERVED1 : 6; }; static_assert(sizeof(HPFSM_4_Type) == sizeof(reg_t), "HPFSM_4_Type wrong size"); struct SPI_EN_Type { reg_t EN_SPI : 1; reg_t CAL_SPI : 1; reg_t LOGEN_SPI_EN : 1; reg_t SYN_SPI_EN : 1; reg_t VAS_SPI_EN : 1; reg_t PADRV_SPI_EN : 1; reg_t PADAC_SPI_EN : 1; reg_t PADAC_TX_EN : 1; reg_t TXMX_SPI_EN : 1; reg_t TXLO_SPI_EN : 1; reg_t RESERVED0 : 6; }; static_assert(sizeof(SPI_EN_Type) == sizeof(reg_t), "SPI_EN_Type wrong size"); struct SYN_FR_DIV_1_Type { reg_t SYN_FRDIV_9_0 : 10; reg_t RESERVED0 : 6; }; static_assert(sizeof(SYN_FR_DIV_1_Type) == sizeof(reg_t), "SYN_FR_DIV_1_Type wrong size"); struct SYN_FR_DIV_2_Type { reg_t SYN_FRDIV_19_10 : 10; reg_t RESERVED0 : 6; }; static_assert(sizeof(SYN_FR_DIV_2_Type) == sizeof(reg_t), "SYN_FR_DIV_2_Type wrong size"); struct SYN_INT_DIV_Type { reg_t SYN_INTDIV : 8; reg_t LOGEN_BSW : 2; reg_t RESERVED0 : 6; }; static_assert(sizeof(SYN_INT_DIV_Type) == sizeof(reg_t), "SYN_INT_DIV_Type wrong size"); struct SYN_CFG_1_Type { reg_t SYN_MODE_FR_EN : 1; reg_t SYN_REF_DIV_RATIO : 2; reg_t SYN_CP_CURRENT : 2; reg_t SYN_CLOCKOUT_DRIVE : 1; reg_t SYN_TURBO_EN : 1; reg_t CP_TRM_SET : 1; reg_t CP_TRM_CODE : 2; reg_t RESERVED0 : 6; }; static_assert(sizeof(SYN_CFG_1_Type) == sizeof(reg_t), "SYN_CFG_1_Type wrong size"); struct SYN_CFG_2_Type { reg_t SYN_CP_COMMON_MODE_EN : 1; reg_t SYN_PRESCALER_BIAS_BOOST : 1; reg_t SYN_CP_BETA_CURRENT_COMP_EN : 1; reg_t SYN_SD_CLK_SEL : 1; reg_t SYN_CP_PW_ADJ : 1; reg_t SYN_CP_LIN_CURRENT_SEL : 2; reg_t SYN_TEST_OUT_SEL : 3; reg_t RESERVED0 : 6; }; static_assert(sizeof(SYN_CFG_2_Type) == sizeof(reg_t), "SYN_CFG_2_Type wrong size"); struct VAS_CFG_Type { reg_t VAS_MODE : 1; reg_t VAS_RELOCK_SEL : 1; reg_t VAS_DIV : 3; reg_t VAS_DLY : 2; reg_t VAS_TRIG_EN : 1; reg_t VAS_ADE : 1; reg_t VAS_ADL_SPI : 1; reg_t RESERVED0 : 6; }; static_assert(sizeof(VAS_CFG_Type) == sizeof(reg_t), "VAS_CFG_Type wrong size"); struct LO_MISC_Type { reg_t VAS_SPI : 5; reg_t XTAL_BIAS_SEL : 2; reg_t XTAL_E2C_BIAS_SEL : 1; reg_t VAS_SE : 1; reg_t VCO_SPI_EN : 1; reg_t RESERVED0 : 6; }; static_assert(sizeof(LO_MISC_Type) == sizeof(reg_t), "LO_MISC_Type wrong size"); struct XTAL_CFG_Type { reg_t XTAL_FTUNE : 7; reg_t XTAL_CLKOUT_EN : 1; reg_t XTAL_CLKOUT_DIV : 1; reg_t XTAL_CORE_EN : 1; reg_t RESERVED0 : 6; }; static_assert(sizeof(XTAL_CFG_Type) == sizeof(reg_t), "XTAL_CFG_Type wrong size"); struct VCO_CFG_Type { reg_t VCO_BIAS_SPI_EN : 1; reg_t VCO_BIAS_SPI : 4; reg_t VCO_CMEN : 1; reg_t VCO_PDET_TST : 2; reg_t VCO_BUF_BIASH : 2; reg_t RESERVED0 : 6; }; static_assert(sizeof(VCO_CFG_Type) == sizeof(reg_t), "VCO_CFG_Type wrong size"); struct LO_GEN_Type { reg_t LOGEN_BIASH1 : 2; reg_t LOGEN_BIASH2 : 1; reg_t LOGEN_2GM : 1; reg_t LOGEN_TRIM1 : 1; reg_t LOGEN_TRIM2 : 1; reg_t VAS_TST : 4; reg_t RESERVED0 : 6; }; static_assert(sizeof(LO_GEN_Type) == sizeof(reg_t), "LO_GEN_Type wrong size"); struct PA_DRV_PA_DAC_Type { reg_t PADRV_BIAS : 3; reg_t PADRV_DOWN_SPI_EN : 1; reg_t PADRV_DOWN_SPI_SEL : 1; reg_t PADAC_IV : 1; reg_t PADAC_VMODE : 1; reg_t PADAC_DIVH : 1; reg_t TXGATE_EN : 1; reg_t TX_DCCORR_EN : 1; reg_t RESERVED0 : 6; }; static_assert(sizeof(PA_DRV_PA_DAC_Type) == sizeof(reg_t), "PA_DRV_PA_DAC_Type wrong size"); struct PA_DAC_Type { reg_t PADAC_BIAS : 6; reg_t PADAC_DLY : 4; reg_t RESERVED0 : 6; }; static_assert(sizeof(PA_DAC_Type) == sizeof(reg_t), "PA_DAC_Type wrong size"); struct TX_GAIN_Type { reg_t TXVGA_GAIN_SPI_EN : 1; reg_t TXVGA_GAIN_MSB_SPI_EN : 1; reg_t TX_DCCORR_SPI_EN : 1; reg_t FUSE_ARM : 1; reg_t TXVGA_GAIN_SPI : 6; reg_t RESERVED0 : 6; }; static_assert(sizeof(TX_GAIN_Type) == sizeof(reg_t), "TX_GAIN_Type wrong size"); struct TX_LO_IQ_Type { reg_t TXLO_IQ_SPI : 5; reg_t TXLO_IQ_SPI_EN : 1; reg_t TXLO_BUFF : 2; reg_t FUSE_GKT : 1; reg_t FUSE_RTH : 1; reg_t RESERVED0 : 6; }; static_assert(sizeof(TX_LO_IQ_Type) == sizeof(reg_t), "TX_LO_IQ_Type wrong size"); struct TX_DC_CORR_Type { reg_t TX_DCCORR_I : 5; reg_t TX_DCCORR_Q : 5; reg_t RESERVED0 : 6; }; static_assert(sizeof(TX_DC_CORR_Type) == sizeof(reg_t), "TX_DC_CORR_Type wrong size"); struct Register_Type { RXRF_1_Type rxrf_1; /* 0 */ RXRF_2_Type rxrf_2; LPF_1_Type lpf_1; LPF_2_Type lpf_2; LPF_3_VGA_1_Type lpf_3_vga_1; /* 4 */ VGA_2_Type vga_2; VGA_3_RX_TOP_Type vga_3_rx_top; TEMP_SENSE_Type temp_sense; RX_TOP_RX_BIAS_Type rx_top_rx_bias; /* 8 */ RX_TOP_Type rx_top; TX_TOP_1_Type tx_top_1; TX_TOP_2_Type tx_top_2; HPFSM_1_Type hpfsm_1; /* 12 */ HPFSM_2_Type hpfsm_2; HPFSM_3_Type hpfsm_3; HPFSM_4_Type hpfsm_4; SPI_EN_Type spi_en; /* 16 */ SYN_FR_DIV_1_Type syn_fr_div_1; SYN_FR_DIV_2_Type syn_fr_div_2; SYN_INT_DIV_Type syn_int_div; SYN_CFG_1_Type syn_cfg_1; /* 20 */ SYN_CFG_2_Type syn_cfg_2; VAS_CFG_Type vas_cfg; LO_MISC_Type lo_misc; XTAL_CFG_Type xtal_cfg; /* 24 */ VCO_CFG_Type vco_cfg; LO_GEN_Type lo_gen; PA_DRV_PA_DAC_Type pa_drv_pa_dac; PA_DAC_Type pa_dac; /* 28 */ TX_GAIN_Type tx_gain; TX_LO_IQ_Type tx_lo_iq; TX_DC_CORR_Type tx_dc_corr; }; 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 w; }; }; static_assert(sizeof(RegisterMap) == reg_count * sizeof(reg_t), "RegisterMap type wrong size"); constexpr RegisterMap initial_register_values { Register_Type { /* Best effort to reconcile default values specified in three * different places in the MAX2837 documentation. */ .rxrf_1 = { /* 0 */ .LNA_EN = 0, .Mixer_EN = 0, .RxLO_EN = 0, .Lbias = 0b10, .Mbias = 0b10, .buf = 0b10, .LNAband = 0, .RESERVED0 = 0, }, .rxrf_2 = { /* 1 */ .LNAtune = 0, .LNAde_Q = 1, .L = 0b000, .iqerr_trim = 0b0000, .RESERVED0 = 0, }, .lpf_1 = { /* 2 */ .LPF_EN = 0, .TxBB_EN = 0, .ModeCtrl = 0b01, .FT = 0b1111, .dF = 0b01, .RESERVED0 = 0, }, .lpf_2 = { /* 3 */ .PT_SPI = 0b1001, .Bqd = 0b011, .TxRPCM = 0b011, .RESERVED0 = 0, }, .lpf_3_vga_1 = { /* 4 */ .RP = 0b10, .TxBuff = 0b10, .VGA_EN = 0, .VGAMUX_enable = 0, .BUFF_Curr = 0b00, .BUFF_VCM = 0b00, .RESERVED0 = 0, }, .vga_2 = { /* 5 */ .VGA = 0b00000, .sel_In1_In2 = 0, .turbo15n20 = 0, .VGA_Curr = 0b01, .fuse_arm = 0, .RESERVED0 = 0, }, .vga_3_rx_top = { /* 6 */ .RESERVED0 = 0b000110, .RSSI_EN_SPIenables = 0, .RSSI_MUX = 0, .RSSI_MODE = 0, .LPF_MODE_SEL = 0, .RESERVED1 = 0, }, .temp_sense = { /* 7 */ .ts_adc = 0b00000, .RESERVED0 = 0, .PLL_test_output = 0, .VAS_test_output = 0, .HPFSM_test_output = 0, .LOGEN_trim_divider_test_output = 0, .RESERVED1 = 0, }, .rx_top_rx_bias = { /* 8 */ .LNAgain_SPI_EN = 0, .VGAgain_SPI_EN = 0, .EN_Bias_Trim = 0, .BIAS_TRIM_SPI = 0b10000, .BIAS_TRIM_CNTRL = 0, .RX_IQERR_SPI_EN = 0, .RESERVED0 = 0, }, .rx_top = { /* 9 */ .ts_adc_trigger = 0, .ts_en = 0, .LPFtrim_SPI_EN = 0, .DOUT_DRVH = 1, /* Documentation mismatch */ .DOUT_PU = 1, .DOUT_SEL = 0b000, .fuse_th = 0, .fuse_burn_gkt = 0, .RESERVED0 = 0, }, .tx_top_1 = { /* 10 */ .RESERVED0 = 0, .TXCAL_GAIN = 0b00, .TXCAL_V2I_FILT = 0b011, .TX_BIAS_ADJ = 0b01, .RESERVED1 = 0b00, .RESERVED2 = 0, }, .tx_top_2 = { /* 11 */ .AMD_SPI_EN = 0, .TXMXR_V2I_GAIN = 0b1011, .RESERVED0 = 0b00000, .RESERVED1 = 0, }, .hpfsm_1 = { /* 12 */ .HPC_10M = 0b11, .HPC_10M_GAIN = 0b11, .HPC_600k = 0b100, .HPC_600k_GAIN = 0b100, .RESERVED0 = 0, }, .hpfsm_2 = { /* 13 */ .HPC_100k = 0b00, .HPC_100k_GAIN = 0b00, .HPC_30k = 0b01, .HPC_30k_GAIN = 0b01, .HPC_1k = 0b01, .RESERVED0 = 0, }, .hpfsm_3 = { /* 14 */ .HPC_1k_GAIN = 0b01, .HPC_DELAY = 0b01, .HPC_STOP = 0b00, .HPC_STOP_M2 = 0b11, .HPC_RXGAIN_EN = 1, .HPC_MODE = 0, .RESERVED0 = 0, }, .hpfsm_4 = { /* 15 */ .HPC_DIVH = 1, .HPC_TST = 0b00000, .HPC_SEQ_BYP = 0, .DOUT_CSB_SEL = 1, /* Documentation mismatch */ .RESERVED0 = 0b00, .RESERVED1 = 0, }, .spi_en = { /* 16 */ .EN_SPI = 0, .CAL_SPI = 0, .LOGEN_SPI_EN = 1, .SYN_SPI_EN = 1, .VAS_SPI_EN = 1, .PADRV_SPI_EN = 0, .PADAC_SPI_EN = 0, .PADAC_TX_EN = 0, .TXMX_SPI_EN = 0, .TXLO_SPI_EN = 0, .RESERVED0 = 0, }, .syn_fr_div_1 = { /* 17 */ .SYN_FRDIV_9_0 = 0b0101010101, .RESERVED0 = 0, }, .syn_fr_div_2 = { /* 18 */ .SYN_FRDIV_19_10 = 0b0101010101, .RESERVED0 = 0, }, .syn_int_div = { /* 19 */ .SYN_INTDIV = 0b01010011, .LOGEN_BSW = 0b01, .RESERVED0 = 0, }, .syn_cfg_1 = { /* 20 */ .SYN_MODE_FR_EN = 1, .SYN_REF_DIV_RATIO = 0b00, .SYN_CP_CURRENT = 0b00, .SYN_CLOCKOUT_DRIVE = 0, .SYN_TURBO_EN = 1, .CP_TRM_SET = 0, .CP_TRM_CODE = 0b10, .RESERVED0 = 0, }, .syn_cfg_2 = { /* 21 */ .SYN_CP_COMMON_MODE_EN = 1, .SYN_PRESCALER_BIAS_BOOST = 0, .SYN_CP_BETA_CURRENT_COMP_EN = 1, .SYN_SD_CLK_SEL = 1, .SYN_CP_PW_ADJ = 0, .SYN_CP_LIN_CURRENT_SEL = 0b01, .SYN_TEST_OUT_SEL = 0b000, .RESERVED0 = 0, }, .vas_cfg = { /* 22 */ .VAS_MODE = 1, .VAS_RELOCK_SEL = 0, .VAS_DIV = 0b010, .VAS_DLY = 0b01, .VAS_TRIG_EN = 1, .VAS_ADE = 1, .VAS_ADL_SPI = 0, .RESERVED0 = 0, }, .lo_misc = { /* 23 */ .VAS_SPI = 0b01111, .XTAL_BIAS_SEL = 0b10, .XTAL_E2C_BIAS_SEL = 0, .VAS_SE = 0, .VCO_SPI_EN = 1, .RESERVED0 = 0, }, .xtal_cfg = { /* 24 */ .XTAL_FTUNE = 0b0000000, .XTAL_CLKOUT_EN = 0, /* 1->0 to "turn off" CLKOUT pin. Doesn't seem to work though... */ .XTAL_CLKOUT_DIV = 1, .XTAL_CORE_EN = 0, .RESERVED0 = 0, }, .vco_cfg = { /* 25 */ .VCO_BIAS_SPI_EN = 0, .VCO_BIAS_SPI = 0b0000, .VCO_CMEN = 0, .VCO_PDET_TST = 0b00, .VCO_BUF_BIASH = 0b01, .RESERVED0 = 0, }, .lo_gen = { /* 26 */ .LOGEN_BIASH1 = 0b10, .LOGEN_BIASH2 = 0, .LOGEN_2GM = 1, .LOGEN_TRIM1 = 0, .LOGEN_TRIM2 = 0, .VAS_TST = 0b1111, .RESERVED0 = 0, }, .pa_drv_pa_dac = { /* 27 */ .PADRV_BIAS = 0b011, .PADRV_DOWN_SPI_EN = 0, .PADRV_DOWN_SPI_SEL = 0, /* Documentation mismatch */ .PADAC_IV = 1, .PADAC_VMODE = 1, .PADAC_DIVH = 1, .TXGATE_EN = 1, .TX_DCCORR_EN = 1, .RESERVED0 = 0, }, .pa_dac = { /* 28 */ .PADAC_BIAS = 0b000000, .PADAC_DLY = 0b0011, .RESERVED0 = 0, }, .tx_gain = { /* 29 */ .TXVGA_GAIN_SPI_EN = 0, .TXVGA_GAIN_MSB_SPI_EN = 0, .TX_DCCORR_SPI_EN = 0, .FUSE_ARM = 0, .TXVGA_GAIN_SPI = 0b111111, .RESERVED0 = 0, }, .tx_lo_iq = { /* 30 */ .TXLO_IQ_SPI = 0b00000, .TXLO_IQ_SPI_EN = 0, .TXLO_BUFF = 0b10, .FUSE_GKT = 0, .FUSE_RTH = 0, .RESERVED0 = 0, }, .tx_dc_corr = { /* 31 */ .TX_DCCORR_I = 0b00000, .TX_DCCORR_Q = 0b00000, .RESERVED0 = 0, }, } }; class MAX2837 { public: constexpr MAX2837( spi::arbiter::Target& target ) : _target(target) { } void init(); void set_mode(const Mode mode); void set_tx_vga_gain(const int_fast8_t value); void set_lna_gain(const int_fast8_t db); void set_vga_gain(const int_fast8_t db); void set_lpf_rf_bandwidth(const uint32_t bandwidth_minimum); #if 0 void rx_cal() { _map.r.spi_en.EN_SPI = 1; _map.r.spi_en.CAL_SPI = 1; flush_one(Register::SPI_EN); _map.r.vga_3_rx_top.LPF_MODE_SEL = 1; flush_one(Register::VGA_3_RX_TOP); _map.r.lpf_1.ModeCtrl = 0b00; flush_one(Register::LPF_1); _map.r.lo_gen.LOGEN_2GM = 1; flush_one(Register::LO_GEN); chThdSleepMilliseconds(100); _map.r.spi_en.CAL_SPI = 0; flush_one(Register::SPI_EN); _map.r.vga_3_rx_top.LPF_MODE_SEL = 0; flush_one(Register::VGA_3_RX_TOP); _map.r.lpf_1.ModeCtrl = 0b01; flush_one(Register::LPF_1); _map.r.lo_gen.LOGEN_2GM = 0; flush_one(Register::LO_GEN); } void test_rx_offset(const size_t n) { _map.r.hpfsm_4.HPC_TST = n; _dirty[Register::HPFSM_4] = 1; /* _map.r.hpfsm_3.HPC_STOP = n; _dirty[Register::HPFSM_3] = 1; */ flush(); } #endif bool set_frequency(const rf::Frequency lo_frequency); reg_t temp_sense(); RegisterMap registers(); private: spi::arbiter::Target& _target; RegisterMap _map { initial_register_values }; DirtyRegisters _dirty; void flush_one(const Register reg); 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(); }; } #endif/*__MAX2837_H__*/