mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-10-01 01:26:06 -04:00
905 lines
20 KiB
C++
905 lines
20 KiB
C++
/*
|
|
* 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 <cstdint>
|
|
#include <array>
|
|
|
|
#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<rf::FrequencyRange, 4> 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<rf::FrequencyRange, 2> 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<uint32_t, 16> 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<reg_t, reg_count> 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<Register, reg_count> _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__*/
|