Files

copied
Last update 2 years 1 month by Gianpaolo Macario
Filesfirmwarecommon
..
rad1o
xapp058
LPC4320_M4_memory.ld
LPC4330_M4_memory.ld
LPC43xx_M0_memory.ld
LPC43xx_M4_M0_image_from_text.ld
LPC43xx_M4_memory.ld
README
bitband.c
bitband.h
clkin.c
clkin.h
configure_file.cmake
cpld_jtag.c
cpld_jtag.h
cpld_xc2c.c
cpld_xc2c.h
crc.c
crc.h
fault_handler.c
fault_handler.h
firmware_info.c
firmware_info.h
gpdma.c
gpdma.h
gpio.h
gpio_lpc.c
gpio_lpc.h
hackrf_core.c
hackrf_core.h
hackrf_ui.c
hackrf_ui.h
i2c_bus.c
i2c_bus.h
i2c_lpc.c
i2c_lpc.h
m0_bin.s.cmake
m0_sleep.c
max2837.c
max2837.h
max2837_regs.def
max2837_target.c
max2837_target.h
max2839.c
max2839.h
max2839_regs.def
max2839_target.c
max2839_target.h
max283x.c
max283x.h
max2871.c
max2871.h
max2871_regs.c
max2871_regs.h
max5864.c
max5864.h
max5864_target.c
max5864_target.h
mixer.c
mixer.h
operacake.c
operacake.h
operacake_sctimer.c
operacake_sctimer.h
platform_detect.c
platform_detect.h
portapack.c
portapack.h
rf_path.c
rf_path.h
rffc5071.c
rffc5071.h
rffc5071_regs.def
rffc5071_spi.c
rffc5071_spi.h
rom_iap.c
rom_iap.h
sct.h
sgpio.c
sgpio.h
si5351c.c
si5351c.h
spi_bus.c
spi_bus.h
spi_ssp.c
spi_ssp.h
streaming.c
streaming.h
tuning.c
tuning.h
ui_portapack.c
ui_portapack.h
ui_rad1o.c
ui_rad1o.h
usb.c
usb.h
usb_queue.c
usb_queue.h
usb_request.c
usb_request.h
usb_standard_request.c
usb_standard_request.h
usb_type.h
w25q80bv.c
w25q80bv.h
w25q80bv_target.c
w25q80bv_target.h
max2839.c
/* * Copyright 2012-2022 Great Scott Gadgets <info@greatscottgadgets.com> * Copyright 2012 Will Code <willcode4@gmail.com> * Copyright 2014 Jared Boone <jared@sharebrained.com> * * 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. */ /* * 'gcc -DTEST -DDEBUG -O2 -o test max2839.c' prints out what test * program would do if it had a real spi library * * 'gcc -DTEST -DBUS_PIRATE -O2 -o test max2839.c' prints out bus * pirate commands to do the same thing. */ #include <stdint.h> #include <string.h> #include "max2839.h" #include "max2839_regs.def" // private register def macros static uint8_t requested_lna_gain = 0; static uint8_t requested_vga_gain = 0; /* Default register values. */ static const uint16_t max2839_regs_default[MAX2839_NUM_REGS] = { 0x000, /* 0 */ 0x00c, /* 1: data sheet says 0x00c but read 0x22c */ 0x080, /* 2 */ 0x1b9, /* 3: data sheet says 0x1b9 but read 0x1b0 */ 0x3e6, /* 4 */ 0x100, /* 5 */ 0x000, /* 6 */ 0x208, /* 7 */ 0x220, /* 8: data sheet says 0x220 but read 0x000 */ 0x018, /* 9 */ 0x00c, /* 10 */ 0x004, /* 11: data sheet says 0x004 but read 0x000 */ 0x24f, /* 12 */ 0x150, /* 13 */ 0x3c5, /* 14 */ 0x201, /* 15 */ 0x01c, /* 16 */ 0x155, /* 17 */ 0x155, /* 18 */ 0x153, /* 19 */ 0x249, /* 20 */ 0x02d, /* 21: data sheet says 0x02d but read 0x13d */ 0x1a9, /* 22 */ 0x24f, /* 23 */ 0x180, /* 24 */ 0x000, /* 25: data sheet says 0x000 but read 0x00a */ 0x3c0, /* 26 */ 0x200, /* 27: data sheet says 0x200 but read 0x22a */ 0x0c0, /* 28 */ 0x03f, /* 29: data sheet says 0x03f but read 0x07f */ 0x300, /* 30: data sheet says 0x300 but read 0x398 */ 0x340}; /* 31: data sheet says 0x340 but read 0x359 */ /* * All of the discrepancies listed above are in fields that either don't matter * or are undocumented except "set to recommended value". We set them to the * data sheet defaults even though the inital part we tested started up with * different settings. */ /* Set up all registers according to defaults specified in docs. */ static void max2839_init(max2839_driver_t* const drv) { drv->target_init(drv); max2839_set_mode(drv, MAX2839_MODE_SHUTDOWN); memcpy(drv->regs, max2839_regs_default, sizeof(drv->regs)); drv->regs_dirty = 0xffffffff; /* Write default register values to chip. */ max2839_regs_commit(drv); } /* * Set up pins for GPIO and SPI control, configure SSP peripheral for SPI, and * set our own default register configuration. */ void max2839_setup(max2839_driver_t* const drv) { max2839_init(drv); /* Use SPI control instead of B0-B7 pins for gain settings. */ set_MAX2839_LNAgain_SPI(drv, 1); set_MAX2839_VGAgain_SPI(drv, 1); set_MAX2839_TX_VGA_Gain_SPI(drv, 1); /* enable RXINB */ set_MAX2839_MIMO_SELECT(drv, 1); /* set gains for unused RXINA path to minimum */ set_MAX2839_LNA1gain(drv, MAX2839_LNA1gain_M32); set_MAX2839_Rx1_VGAgain(drv, 0x3f); /* set maximum RX output common-mode voltage */ set_MAX2839_RX_VCM(drv, MAX2839_RX_VCM_1_35); /* set HPF corner frequency to 1 kHz */ set_MAX2839_HPC_STOP(drv, MAX2839_STOP_1K); /* * There are two LNA band settings, but we only use one of them. * Switching to the other one doesn't make the overall spectrum any * flatter but adds a surprise step in the middle. */ set_MAX2839_LNAband(drv, MAX2839_LNAband_2_4); max2839_regs_commit(drv); } static uint16_t max2839_read(max2839_driver_t* const drv, uint8_t r) { uint16_t value = (1 << 15) | (r << 10); spi_bus_transfer(drv->bus, &value, 1); return value & 0x3ff; } static void max2839_write(max2839_driver_t* const drv, uint8_t r, uint16_t v) { uint16_t value = (r << 10) | (v & 0x3ff); spi_bus_transfer(drv->bus, &value, 1); } uint16_t max2839_reg_read(max2839_driver_t* const drv, uint8_t r) { // always read actual value from SPI for now //if ((drv->regs_dirty >> r) & 0x1) { drv->regs[r] = max2839_read(drv, r); //}; return drv->regs[r]; } void max2839_reg_write(max2839_driver_t* const drv, uint8_t r, uint16_t v) { drv->regs[r] = v; max2839_write(drv, r, v); MAX2839_REG_SET_CLEAN(drv, r); } static inline void max2839_reg_commit(max2839_driver_t* const drv, uint8_t r) { max2839_reg_write(drv, r, drv->regs[r]); } void max2839_regs_commit(max2839_driver_t* const drv) { int r; for (r = 0; r < MAX2839_NUM_REGS; r++) { if ((drv->regs_dirty >> r) & 0x1) { max2839_reg_commit(drv, r); } } } void max2839_set_mode(max2839_driver_t* const drv, const max2839_mode_t new_mode) { drv->set_mode(drv, new_mode); } max2839_mode_t max2839_mode(max2839_driver_t* const drv) { return drv->mode; } void max2839_start(max2839_driver_t* const drv) { 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) { // FIXME does this do anything without LPFmode_SPI set? // do we need it to? set_MAX2839_LPFmode(drv, MAX2839_LPFmode_TxLPF); max2839_regs_commit(drv); max2839_set_mode(drv, MAX2839_MODE_TX); } void max2839_rx(max2839_driver_t* const drv) { set_MAX2839_LPFmode(drv, MAX2839_LPFmode_RxLPF); max2839_regs_commit(drv); max2839_set_mode(drv, MAX2839_MODE_RX); } void max2839_stop(max2839_driver_t* const drv) { 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) { uint8_t 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; } else if (freq < 2500000000U) { band = MAX2839_LOGEN_BSW_2_4; } else if (freq < 2600000000U) { band = MAX2839_LOGEN_BSW_2_5; } else { band = MAX2839_LOGEN_BSW_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); /* 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 { uint32_t bandwidth_hz; uint32_t ft; } max2839_ft_t; // clang-format off static const max2839_ft_t max2839_ft[] = { { 1750000, MAX2839_FT_1_75M }, { 2500000, MAX2839_FT_2_5M }, { 3500000, MAX2839_FT_3_5M }, { 5000000, MAX2839_FT_5M }, { 5500000, MAX2839_FT_5_5M }, { 6000000, MAX2839_FT_6M }, { 7000000, MAX2839_FT_7M }, { 8000000, MAX2839_FT_8M }, { 9000000, MAX2839_FT_9M }, { 10000000, MAX2839_FT_10M }, { 12000000, MAX2839_FT_12M }, { 14000000, MAX2839_FT_14M }, { 15000000, MAX2839_FT_15M }, { 20000000, MAX2839_FT_20M }, { 24000000, MAX2839_FT_24M }, { 28000000, MAX2839_FT_28M }, { 0, 0 }, }; //clang-format on uint32_t max2839_set_lpf_bandwidth(max2839_driver_t* const drv, const uint32_t bandwidth_hz) { const max2839_ft_t* p = max2839_ft; while( p->bandwidth_hz != 0 ) { if( p->bandwidth_hz >= bandwidth_hz ) { break; } p++; } if( p->bandwidth_hz != 0 ) { set_MAX2839_FT(drv, p->ft); max2839_regs_commit(drv); } return p->bandwidth_hz; } void max2839_configure_rx_gain(max2839_driver_t* const drv) { /* * restrict requested LNA gain to valid MAX2837 settings: * 0, 8, 16, 24, 32, or 40 */ if (requested_lna_gain > 40) { requested_lna_gain = 40; } requested_lna_gain &= 0x38; /* * restrict requested VGA gain to valid MAX2837 settings: * even number, 0 through 62 */ if (requested_vga_gain > 62) { requested_vga_gain = 62; } requested_vga_gain &= 0x3e; /* * MAX2839 has lower full-scale RX output voltage than MAX2837, so we * adjust the VGA (baseband) gain to compensate. */ uint8_t vga_gain = requested_vga_gain + 3; uint8_t lna_gain = requested_lna_gain; /* * If that adjustment puts VGA gain out of range, use LNA gain to * compensate. MAX2839 VGA gain can be any number from 0 through 63. */ if (vga_gain > 63) { if (lna_gain <= 32) { vga_gain -= 8; lna_gain += 8; } else { vga_gain = 63; } } /* * MAX2839 lacks max-24 dB and max-40 dB LNA gain settings, so we use * VGA gain to compensate. */ if (lna_gain == 0) { lna_gain = 8; vga_gain = (vga_gain >= 8) ? vga_gain - 8 : 0; } if (lna_gain == 16) { if (vga_gain > 32) { vga_gain -= 8; lna_gain += 8; } else { vga_gain += 8; lna_gain -= 8; } } uint16_t val; switch (lna_gain) { case 40: val = MAX2839_LNA2gain_MAX; break; case 32: val = MAX2839_LNA2gain_M8; break; case 24: case 16: val = MAX2839_LNA2gain_M16; break; case 8: case 0: default: val = MAX2839_LNA2gain_M32; break; } set_MAX2839_LNA2gain(drv, val); set_MAX2839_Rx2_VGAgain(drv, (63 - vga_gain)); max2839_regs_commit(drv); } bool max2839_set_lna_gain(max2839_driver_t* const drv, const uint32_t gain_db) { if ((gain_db & 0x7) || gain_db > 40) { return false; } requested_lna_gain = gain_db; max2839_configure_rx_gain(drv); return true; } bool max2839_set_vga_gain(max2839_driver_t* const drv, const uint32_t gain_db) { if ((gain_db & 0x1) || gain_db > 62) { return false; } requested_vga_gain = gain_db; max2839_configure_rx_gain(drv); return true; } bool max2839_set_txvga_gain(max2839_driver_t* const drv, const uint32_t gain_db) { uint16_t val = 0; val = 47 - gain_db; set_MAX2839_TX_VGA_GAIN(drv, val); max2839_reg_commit(drv, 29); return true; }
Report a bug