From 14183a96eac0c34e06f290a8b0f0d62e26534488 Mon Sep 17 00:00:00 2001 From: grvvy Date: Wed, 14 Sep 2022 12:49:45 -0600 Subject: [PATCH] h1r9: implement additional MAX2839 functions, change some mreg definition names, fix RF gain control math --- firmware/common/max2839.c | 94 +++++++++++++++++++++++--------- firmware/common/max2839_regs.def | 36 +++++++----- 2 files changed, 91 insertions(+), 39 deletions(-) diff --git a/firmware/common/max2839.c b/firmware/common/max2839.c index b10e9881..c21cf93d 100644 --- a/firmware/common/max2839.c +++ b/firmware/common/max2839.c @@ -56,11 +56,6 @@ static const uint16_t max2839_regs_default[MAX2839_NUM_REGS] = { 0x155, /* 18 */ 0x153, /* 19 */ 0x249, /* 20 */ - /* - * Charge Pump Common Mode Enable bit (0) of register 21 must be set or TX - * does not work. Page 1 of the SPI doc says not to set it (0x02c), but - * page 21 says it should be set by default (0x02d). - */ 0x02d, /* 21 */ 0x1a9, /* 22 */ 0x24f, /* 23 */ @@ -83,7 +78,7 @@ static void max2839_init(max2839_driver_t* const drv) drv->regs_dirty = 0xffffffff; /* Write default register values to chip. */ - max2837_regs_commit(drv); + max2839_regs_commit(drv); } /* @@ -152,35 +147,85 @@ max2839_mode_t max2839_mode(max2839_driver_t* const drv) void max2839_start(max2839_driver_t* const drv) { - set_MAX2839_EN_SPI(drv, 1); + set_MAX2839_chip_enable(drv, 1); max2839_regs_commit(drv); max2839_set_mode(drv, MAX2839_MODE_STANDBY); } void max2839_tx(max2839_driver_t* const drv) { - // TODO + set_MAX2839_LPFblock_MODE(drv, MAX2839_ModeCtrl_TxLPF); max2839_regs_commit(drv); max2839_set_mode(drv, MAX2839_MODE_TX); } void max2839_rx(max2839_driver_t* const drv) { - // TODO + set_MAX2839_LPFblock_MODE(drv, MAX2839_ModeCtrl_RxLPF); max2839_regs_commit(drv); max2839_set_mode(drv, MAX2839_MODE_RX); } void max2839_stop(max2839_driver_t* const drv) { - // TODO + set_MAX2839_chip_enable(drv, 0); max2839_regs_commit(drv); max2839_set_mode(drv, MAX2839_MODE_SHUTDOWN); } void max2839_set_frequency(max2839_driver_t* const drv, uint32_t freq) { - // TODO + uint8_t band; + uint8_t lna_band; + uint32_t div_frac; + uint32_t div_int; + uint32_t div_rem; + uint32_t div_cmp; + int i; + + /* Select band. Allow tuning outside specified bands. */ + if (freq < 2400000000U) { + band = MAX2839_LOGEN_BSW_2_3; + lna_band = MAX2839_LNAband_2_4; + } else if (freq < 2500000000U) { + band = MAX2839_LOGEN_BSW_2_4; + lna_band = MAX2839_LNAband_2_4; + } else if (freq < 2600000000U) { + band = MAX2839_LOGEN_BSW_2_5; + lna_band = MAX2839_LNAband_2_6; + } else { + band = MAX2839_LOGEN_BSW_2_6; + lna_band = MAX2839_LNAband_2_6; + } + + /* ASSUME 40MHz PLL. Ratio = F*(4/3)/40,000,000 = F/30,000,000 */ + div_int = freq / 30000000; + div_rem = freq % 30000000; + div_frac = 0; + div_cmp = 30000000; + for (i = 0; i < 20; i++) { + div_frac <<= 1; + div_cmp >>= 1; + if (div_rem > div_cmp) { + div_frac |= 0x1; + div_rem -= div_cmp; + } + } + + /* Band settings */ + set_MAX2839_LOGEN_BSW(drv, band); + set_MAX2839_LNAband(drv, lna_band); + + /* Write order matters here, so commit INT and FRAC_HI before + * committing FRAC_LO, which is the trigger for VCO + * auto-select. TODO - it's cleaner this way, but it would be + * faster to explicitly commit the registers explicitly so the + * dirty bits aren't scanned twice. */ + set_MAX2839_SYN_INT(drv, div_int); + set_MAX2839_SYN_FRAC_HI(drv, (div_frac >> 10) & 0x3ff); + max2839_regs_commit(drv); + set_MAX2839_SYN_FRAC_LO(drv, div_frac & 0x3ff); + max2839_regs_commit(drv); } typedef struct { @@ -229,25 +274,27 @@ uint32_t max2839_set_lpf_bandwidth(max2839_driver_t* const drv, const uint32_t b bool max2839_set_lna_gain(max2839_driver_t* const drv, const uint32_t gain_db) { uint16_t val; - // TODO: validate steps here switch(gain_db){ case 40: - val = MAX2839_LNAgain_MAX; + val = MAX2839_LNA1gain_MAX; break; case 32: - val = MAX2839_LNAgain_M8; + val = MAX2839_LNA1gain_M8; break; case 24: - val = MAX2839_LNAgain_M16; + val = MAX2839_LNA1gain_M16; break; case 8: - val = MAX2839_LNAgain_M32; + val = MAX2839_LNA1gain_M32; + break; + case 0: + val = MAX2839_LNA1gain_M32; break; default: return false; } - set_MAX2839_LNAgain(drv, val); - max2839_reg_commit(drv, 1); + set_MAX2839_LNA1gain(drv, val); + max2839_reg_commit(drv, 5); return true; } @@ -256,21 +303,16 @@ bool max2839_set_vga_gain(max2839_driver_t* const drv, const uint32_t gain_db) { return false; } - set_MAX2839_VGA(drv, 31-(gain_db >> 1) ); + set_MAX2839_Rx1_VGAgain(drv, (63-gain_db)); max2839_reg_commit(drv, 5); return true; } bool max2839_set_txvga_gain(max2839_driver_t* const drv, const uint32_t gain_db) { uint16_t val=0; - if(gain_db <16){ - val = 31-gain_db; - val |= (1 << 5); // bit6: 16db - } else{ - val = 31-(gain_db-16); - } + val = 63-gain_db; - set_MAX2839_TXVGA_GAIN(drv, val); + set_MAX2839_TX_VGA_GAIN(drv, val); max2839_reg_commit(drv, 29); return true; } diff --git a/firmware/common/max2839_regs.def b/firmware/common/max2839_regs.def index 9bc72410..821d1dda 100644 --- a/firmware/common/max2839_regs.def +++ b/firmware/common/max2839_regs.def @@ -31,7 +31,9 @@ static inline void set_##n(max2839_driver_t* const _d, uint16_t v) { \ __MREG__(MAX2839_RESERVED_1, 0,9,10) /* REG 1 */ -__MREG__(MAX2839_LNAtune,1,1,2) +__MREG__(MAX2839_LNAband,1,1,2) +#define MAX2839_LNAband_2_4 0 // 2.3-2.5 GHz +#define MAX2839_LNAband_2_6 1 // 2.5-2.7 GHz __MREG__(MAX2839_RESERVED_2,1,2,1) __MREG__(MAX2839_MIMO_SELECT,1,3,1) __MREG__(MAX2839_iqerr_trim,1,9,6) @@ -53,7 +55,7 @@ __MREG__(MAX2839_RESERVED_5,3,9,10) __MREG__(MAX2839_RESERVED_6,4,1,2) __MREG__(MAX2839_LPF_CUTOFF,4,3,2) __MREG__(MAX2839_RESERVED_7,4,5,2) -__MREG__(MAX2839_LPF_RF_BAND,4,9,4) +__MREG__(MAX2839_FT,4,9,4) #define MAX2839_FT_1_75M 0 #define MAX2839_FT_2_5M 1 #define MAX2839_FT_3_5M 2 @@ -72,13 +74,17 @@ __MREG__(MAX2839_LPF_RF_BAND,4,9,4) #define MAX2839_FT_28M 15 /* REG 5 */ -__MREG__(MAX2839_LNA1gain_SPI,5,1,2) -#define MAX2839_LNAgain_MAX 0b000 // Pad in 8dB steps, bits reversed -#define MAX2839_LNAgain_M8 0b001 -#define MAX2839_LNAgain_M16 0b010 -#define MAX2839_LNAgain_M32 0b011 +__MREG__(MAX2839_LNA1gain,5,1,2) +#define MAX2839_LNA1gain_MAX 0b000 // Pad in 8dB steps, bits reversed +#define MAX2839_LNA1gain_M8 0b001 +#define MAX2839_LNA1gain_M16 0b010 +#define MAX2839_LNA1gain_M32 0b011 __MREG__(MAX2839_Rx1_VGAgain,5,7,6) __MREG__(MAX2839_LPFblock_MODE,5,9,2) +#define MAX2839_ModeCtrl_RxCalibration 0 +#define MAX2839_ModeCtrl_RxLPF 1 +#define MAX2839_ModeCtrl_TxLPF 2 +#define MAX2839_ModeCtrl_LPFTrim 3 /* REG 6 */ __MREG__(MAX2839_LNA2gain_SPI,6,1,2) @@ -146,7 +152,7 @@ __MREG__(MAX2839_RESERVED_15,15,8,2) __MREG__(MAX2839_RXHP_highpass_corner,15,9,1) /* REG 16 */ -__MREG__(MAX2839_chip_disable,16,0,1) +__MREG__(MAX2839_chip_enable,16,0,1) __MREG__(MAX2839_RXTX_calibration_enable,16,1,1) __MREG__(MAX2839_RESERVED_16,16,5,4) __MREG__(MAX2839_PA_bias_DAC_SPI_enable,16,6,1) @@ -154,14 +160,18 @@ __MREG__(MAX2839_PA_bias_DAC_TX_mode_enable,16,7,1) __MREG__(MAX2839_RESERVED_17,16,9,2) /* REG 17 */ -__MREG__(MAX2839_SYNTH_20bit_FDR_UH,17,9,10) +__MREG__(MAX2839_SYN_FRAC_LO,17,9,10) /* REG 18 */ -__MREG__(MAX2839_SYNTH_20bit_FDR_LH,18,9,10) +__MREG__(MAX2839_SYN_FRAC_HI,18,9,10) /* REG 19 */ -__MREG__(MAX2839_SYNTH_8bit_IDR,19,7,8) -__MREG__(MAX2839_LO_Gen_Band_Switch,19,9,2) +__MREG__(MAX2839_SYN_INT,19,7,8) +__MREG__(MAX2839_LOGEN_BSW,19,9,2) +#define MAX2839_LOGEN_BSW_2_3 0 // 2300 - <2400 MHz +#define MAX2839_LOGEN_BSW_2_4 1 // 2400 - <2500 MHz +#define MAX2839_LOGEN_BSW_2_5 2 // 2500 - <2600 MHz +#define MAX2839_LOGEN_BSW_2_6 3 // 2600 - <2700 MHz /* REG 20 */ __MREG__(MAX2839_RESERVED_18,20,0,1) @@ -213,7 +223,7 @@ __MREG__(MAX2839_PADAC_Output_Current_Ctrl,28,5,6) __MREG__(MAX2839_PADAC_TurnOn_Delay_Ctrl,28,9,4) /* REG 29 */ -__MREG__(MAX2839_TX_VGA_SPI_Gain_Ctrl_Addr27,29,5,6) +__MREG__(MAX2839_TX_VGA_GAIN,29,5,6) __MREG__(MAX2839_RESERVED_29,29,9,4) /* REG 30 */