Formatted code (#1007)

* Updated style

* Updated files

* fixed new line

* Updated spacing

* File fix WIP

* Updated to clang 13

* updated comment style

* Removed old comment code
This commit is contained in:
jLynx
2023-05-19 08:16:05 +12:00
committed by GitHub
parent 7aca7ce74d
commit 033c4e9a5b
599 changed files with 70746 additions and 66896 deletions

View File

@@ -24,16 +24,16 @@
#include "utility.hpp"
bool Debounce::feed(const uint8_t bit) {
history_ = (history_ << 1) | (bit & 1);
history_ = (history_ << 1) | (bit & 1);
if( history_ == 0b00001111 ) {
state_ = 1;
return true;
}
if( history_ == 0b11110000 ) {
state_ = 0;
return true;
}
if (history_ == 0b00001111) {
state_ = 1;
return true;
}
if (history_ == 0b11110000) {
state_ = 0;
return true;
}
return false;
return false;
}

View File

@@ -25,16 +25,16 @@
#include <cstdint>
class Debounce {
public:
bool feed(const uint8_t bit);
uint8_t state() const {
return state_;
}
public:
bool feed(const uint8_t bit);
private:
uint8_t history_ { 0 };
uint8_t state_ { 0 };
uint8_t state() const {
return state_;
}
private:
uint8_t history_{0};
uint8_t state_{0};
};
#endif/*__DEBOUNCE_H__*/
#endif /*__DEBOUNCE_H__*/

View File

@@ -24,32 +24,31 @@
#include "utility.hpp"
static const int8_t transition_map[] = {
0, // 0000: noop
0, // 0001: start
0, // 0010: start
0, // 0011: rate
1, // 0100: end
0, // 0101: noop
0, // 0110: rate
-1, // 0111: end
-1, // 1000: end
0, // 1001: rate
0, // 1010: noop
1, // 1011: end
0, // 1100: rate
0, // 1101: start
0, // 1110: start
0, // 1111: noop
0, // 0000: noop
0, // 0001: start
0, // 0010: start
0, // 0011: rate
1, // 0100: end
0, // 0101: noop
0, // 0110: rate
-1, // 0111: end
-1, // 1000: end
0, // 1001: rate
0, // 1010: noop
1, // 1011: end
0, // 1100: rate
0, // 1101: start
0, // 1110: start
0, // 1111: noop
};
int_fast8_t Encoder::update(
const uint_fast8_t phase_0,
const uint_fast8_t phase_1
) {
state <<= 1;
state |= phase_0;
state <<= 1;
state |= phase_1;
const uint_fast8_t phase_0,
const uint_fast8_t phase_1) {
state <<= 1;
state |= phase_0;
state <<= 1;
state |= phase_1;
return transition_map[state & 0xf];
return transition_map[state & 0xf];
}

View File

@@ -25,14 +25,13 @@
#include <cstdint>
class Encoder {
public:
int_fast8_t update(
const uint_fast8_t phase_0,
const uint_fast8_t phase_1
);
public:
int_fast8_t update(
const uint_fast8_t phase_0,
const uint_fast8_t phase_1);
private:
uint_fast8_t state { 0 };
private:
uint_fast8_t state{0};
};
#endif/*__ENCODER_H__*/
#endif /*__ENCODER_H__*/

View File

@@ -38,14 +38,13 @@ namespace lna {
using namespace max283x::lna;
constexpr std::array<uint8_t, 8> lookup_8db_steps {
0b111, 0b011, 0b110, 0b010,
0b100, 0b000, 0b000, 0b000
};
constexpr std::array<uint8_t, 8> lookup_8db_steps{
0b111, 0b011, 0b110, 0b010,
0b100, 0b000, 0b000, 0b000};
static uint_fast8_t gain_ordinal(const int8_t db) {
const auto db_sat = gain_db_range.clip(db);
return lna::lookup_8db_steps[(db_sat >> 3) & 7];
const auto db_sat = gain_db_range.clip(db);
return lna::lookup_8db_steps[(db_sat >> 3) & 7];
}
} /* namespace lna */
@@ -55,8 +54,8 @@ namespace vga {
using namespace max283x::vga;
static uint_fast8_t gain_ordinal(const int8_t db) {
const auto db_sat = gain_db_range.clip(db);
return ((db_sat >> 1) & 0b11111) ^ 0b11111;
const auto db_sat = gain_db_range.clip(db);
return ((db_sat >> 1) & 0b11111) ^ 0b11111;
}
} /* namespace vga */
@@ -66,11 +65,11 @@ namespace tx {
using namespace max283x::tx;
static uint_fast8_t gain_ordinal(const int8_t db) {
const auto db_sat = gain_db_range.clip(db);
uint8_t value = db_sat & 0x0f;
value = (db_sat >= 16) ? (value | 0x20) : value;
value = (db_sat >= 32) ? (value | 0x10) : value;
return (value & 0b111111) ^ 0b111111;
const auto db_sat = gain_db_range.clip(db);
uint8_t value = db_sat & 0x0f;
value = (db_sat >= 16) ? (value | 0x20) : value;
value = (db_sat >= 32) ? (value | 0x10) : value;
return (value & 0b111111) ^ 0b111111;
}
} /* namespace tx */
@@ -80,10 +79,10 @@ namespace filter {
using namespace max283x::filter;
static uint_fast8_t bandwidth_ordinal(const uint32_t bandwidth) {
/* Determine filter setting that will provide bandwidth greater than or
* equal to requested bandwidth.
*/
return std::lower_bound(bandwidths.cbegin(), bandwidths.cend(), bandwidth) - bandwidths.cbegin();
/* Determine filter setting that will provide bandwidth greater than or
* equal to requested bandwidth.
*/
return std::lower_bound(bandwidths.cbegin(), bandwidths.cend(), bandwidth) - bandwidths.cbegin();
}
} /* namespace filter */
@@ -98,36 +97,36 @@ constexpr uint32_t reference_frequency = max283x_reference_f;
constexpr uint32_t pll_factor = 1.0 / (4.0 / 3.0 / reference_frequency) + 0.5;
void MAX2837::init() {
set_mode(Mode::Shutdown);
set_mode(Mode::Shutdown);
gpio_max283x_enable.output();
gpio_max2837_rxenable.output();
gpio_max2837_txenable.output();
gpio_max283x_enable.output();
gpio_max2837_rxenable.output();
gpio_max2837_txenable.output();
_map.r.tx_gain.TXVGA_GAIN_SPI_EN = 1;
_map.r.tx_gain.TXVGA_GAIN_MSB_SPI_EN = 1;
_map.r.tx_gain.TXVGA_GAIN_SPI = 0x00;
_map.r.tx_gain.TXVGA_GAIN_SPI_EN = 1;
_map.r.tx_gain.TXVGA_GAIN_MSB_SPI_EN = 1;
_map.r.tx_gain.TXVGA_GAIN_SPI = 0x00;
_map.r.lpf_3_vga_1.VGAMUX_enable = 1;
_map.r.lpf_3_vga_1.VGA_EN = 1;
_map.r.lpf_3_vga_1.VGAMUX_enable = 1;
_map.r.lpf_3_vga_1.VGA_EN = 1;
_map.r.hpfsm_3.HPC_STOP = 1; /* 1kHz */
_map.r.hpfsm_3.HPC_STOP = 1; /* 1kHz */
_map.r.rx_top_rx_bias.LNAgain_SPI_EN = 1; /* control LNA gain from SPI */
_map.r.rxrf_2.L = 0b000;
_map.r.rx_top_rx_bias.LNAgain_SPI_EN = 1; /* control LNA gain from SPI */
_map.r.rxrf_2.L = 0b000;
_map.r.rx_top_rx_bias.VGAgain_SPI_EN = 1; /* control VGA gain from SPI */
_map.r.vga_2.VGA = 0b01010;
_map.r.rx_top_rx_bias.VGAgain_SPI_EN = 1; /* control VGA gain from SPI */
_map.r.vga_2.VGA = 0b01010;
_map.r.lpf_3_vga_1.BUFF_VCM = 0b00; /* TODO: Check values out of ADC */
_map.r.lpf_3_vga_1.BUFF_VCM = 0b00; /* TODO: Check values out of ADC */
_map.r.lpf_1.LPF_EN = 1; /* Enable low-pass filter */
_map.r.lpf_1.ModeCtrl = 0b01; /* Rx LPF */
_map.r.lpf_1.FT = 0b0000; /* 5MHz LPF */
_map.r.lpf_1.LPF_EN = 1; /* Enable low-pass filter */
_map.r.lpf_1.ModeCtrl = 0b01; /* Rx LPF */
_map.r.lpf_1.FT = 0b0000; /* 5MHz LPF */
_map.r.spi_en.EN_SPI = 1; /* enable chip functions when ENABLE pin set */
_map.r.spi_en.EN_SPI = 1; /* enable chip functions when ENABLE pin set */
_map.r.lo_gen.LOGEN_2GM = 0;
_map.r.lo_gen.LOGEN_2GM = 0;
#if 0
_map.r.rxrf_1.LNA_EN = 1;
@@ -141,184 +140,188 @@ void MAX2837::init() {
_map.r.xtal_cfg.XTAL_CLKOUT_EN = 0; /* CLKOUT pin disabled. (Seems to have no effect.) */
#endif
_map.r.vga_3_rx_top.RSSI_EN_SPIenables = 1;
_map.r.vga_3_rx_top.RSSI_MODE = 1; /* RSSI independent of RXHP */
_map.r.vga_3_rx_top.RSSI_EN_SPIenables = 1;
_map.r.vga_3_rx_top.RSSI_MODE = 1; /* RSSI independent of RXHP */
_dirty.set();
flush();
_dirty.set();
flush();
set_mode(Mode::Standby);
set_mode(Mode::Standby);
}
enum class Mask {
Enable = 0b001,
RxEnable = 0b010,
TxEnable = 0b100,
Shutdown = 0b000,
Standby = Enable,
Receive = Enable | RxEnable,
Transmit = Enable | TxEnable,
Enable = 0b001,
RxEnable = 0b010,
TxEnable = 0b100,
Shutdown = 0b000,
Standby = Enable,
Receive = Enable | RxEnable,
Transmit = Enable | TxEnable,
};
Mask mode_mask(const Mode mode) {
switch (mode) {
case Mode::Standby: return Mask::Standby;
case Mode::Receive: return Mask::Receive;
case Mode::Transmit: return Mask::Transmit;
default: return Mask::Shutdown;
}
switch (mode) {
case Mode::Standby:
return Mask::Standby;
case Mode::Receive:
return Mask::Receive;
case Mode::Transmit:
return Mask::Transmit;
default:
return Mask::Shutdown;
}
}
void MAX2837::set_mode(const Mode mode) {
Mask mask = mode_mask(mode);
gpio_max283x_enable.write(toUType(mask) & toUType(Mask::Enable));
gpio_max2837_rxenable.write(toUType(mask) & toUType(Mask::RxEnable));
gpio_max2837_txenable.write(toUType(mask) & toUType(Mask::TxEnable));
Mask mask = mode_mask(mode);
gpio_max283x_enable.write(toUType(mask) & toUType(Mask::Enable));
gpio_max2837_rxenable.write(toUType(mask) & toUType(Mask::RxEnable));
gpio_max2837_txenable.write(toUType(mask) & toUType(Mask::TxEnable));
}
void MAX2837::flush() {
if( _dirty ) {
for(size_t n=0; n<reg_count; n++) {
if( _dirty[n] ) {
write(n, _map.w[n]);
}
}
_dirty.clear();
}
if (_dirty) {
for (size_t n = 0; n < reg_count; n++) {
if (_dirty[n]) {
write(n, _map.w[n]);
}
}
_dirty.clear();
}
}
void MAX2837::flush_one(const Register reg) {
const auto reg_num = toUType(reg);
write(reg_num, _map.w[reg_num]);
_dirty.clear(reg_num);
const auto reg_num = toUType(reg);
write(reg_num, _map.w[reg_num]);
_dirty.clear(reg_num);
}
void MAX2837::write(const address_t reg_num, const reg_t value) {
uint16_t t = (0U << 15) | (reg_num << 10) | (value & 0x3ffU);
_target.transfer(&t, 1);
uint16_t t = (0U << 15) | (reg_num << 10) | (value & 0x3ffU);
_target.transfer(&t, 1);
}
reg_t MAX2837::read(const address_t reg_num) {
uint16_t t = (1U << 15) | (reg_num << 10);
_target.transfer(&t, 1U);
return t & 0x3ffU;
uint16_t t = (1U << 15) | (reg_num << 10);
_target.transfer(&t, 1U);
return t & 0x3ffU;
}
void MAX2837::write(const Register reg, const reg_t value) {
write(toUType(reg), value);
write(toUType(reg), value);
}
reg_t MAX2837::read(const Register reg) {
return read(toUType(reg));
return read(toUType(reg));
}
void MAX2837::set_tx_vga_gain(const int_fast8_t db) {
_map.r.tx_gain.TXVGA_GAIN_SPI = tx::gain_ordinal(db);
_dirty[Register::TX_GAIN] = 1;
flush();
_map.r.tx_gain.TXVGA_GAIN_SPI = tx::gain_ordinal(db);
_dirty[Register::TX_GAIN] = 1;
flush();
}
void MAX2837::set_lna_gain(const int_fast8_t db) {
_map.r.rxrf_2.L = lna::gain_ordinal(db);
_dirty[Register::RXRF_2] = 1;
flush();
_map.r.rxrf_2.L = lna::gain_ordinal(db);
_dirty[Register::RXRF_2] = 1;
flush();
}
void MAX2837::set_vga_gain(const int_fast8_t db) {
_map.r.vga_2.VGA = vga::gain_ordinal(db);
_dirty[Register::VGA_2] = 1;
flush();
_map.r.vga_2.VGA = vga::gain_ordinal(db);
_dirty[Register::VGA_2] = 1;
flush();
}
void MAX2837::set_lpf_rf_bandwidth(const uint32_t bandwidth_minimum) {
_map.r.lpf_1.FT = filter::bandwidth_ordinal(bandwidth_minimum);
_dirty[Register::LPF_1] = 1;
flush();
_map.r.lpf_1.FT = filter::bandwidth_ordinal(bandwidth_minimum);
_dirty[Register::LPF_1] = 1;
flush();
}
bool MAX2837::set_frequency(const rf::Frequency lo_frequency) {
/* TODO: This is a sad implementation. Refactor. */
if( lo::band[0].contains(lo_frequency) ) {
_map.r.syn_int_div.LOGEN_BSW = 0b00; /* 2300 - 2399.99MHz */
_map.r.rxrf_1.LNAband = 0; /* 2.3 - 2.5GHz */
} else if( lo::band[1].contains(lo_frequency) ) {
_map.r.syn_int_div.LOGEN_BSW = 0b01; /* 2400 - 2499.99MHz */
_map.r.rxrf_1.LNAband = 0; /* 2.3 - 2.5GHz */
} else if( lo::band[2].contains(lo_frequency) ) {
_map.r.syn_int_div.LOGEN_BSW = 0b10; /* 2500 - 2599.99MHz */
_map.r.rxrf_1.LNAband = 1; /* 2.5 - 2.7GHz */
} else if( lo::band[3].contains(lo_frequency) ) {
_map.r.syn_int_div.LOGEN_BSW = 0b11; /* 2600 - 2700Hz */
_map.r.rxrf_1.LNAband = 1; /* 2.5 - 2.7GHz */
} else {
return false;
}
_dirty[Register::SYN_INT_DIV] = 1;
_dirty[Register::RXRF_1] = 1;
/* TODO: This is a sad implementation. Refactor. */
if (lo::band[0].contains(lo_frequency)) {
_map.r.syn_int_div.LOGEN_BSW = 0b00; /* 2300 - 2399.99MHz */
_map.r.rxrf_1.LNAband = 0; /* 2.3 - 2.5GHz */
} else if (lo::band[1].contains(lo_frequency)) {
_map.r.syn_int_div.LOGEN_BSW = 0b01; /* 2400 - 2499.99MHz */
_map.r.rxrf_1.LNAband = 0; /* 2.3 - 2.5GHz */
} else if (lo::band[2].contains(lo_frequency)) {
_map.r.syn_int_div.LOGEN_BSW = 0b10; /* 2500 - 2599.99MHz */
_map.r.rxrf_1.LNAband = 1; /* 2.5 - 2.7GHz */
} else if (lo::band[3].contains(lo_frequency)) {
_map.r.syn_int_div.LOGEN_BSW = 0b11; /* 2600 - 2700Hz */
_map.r.rxrf_1.LNAband = 1; /* 2.5 - 2.7GHz */
} else {
return false;
}
_dirty[Register::SYN_INT_DIV] = 1;
_dirty[Register::RXRF_1] = 1;
const uint64_t div_q20 = (lo_frequency * (1 << 20)) / pll_factor;
const uint64_t div_q20 = (lo_frequency * (1 << 20)) / pll_factor;
_map.r.syn_int_div.SYN_INTDIV = div_q20 >> 20;
_dirty[Register::SYN_INT_DIV] = 1;
_map.r.syn_fr_div_2.SYN_FRDIV_19_10 = (div_q20 >> 10) & 0x3ff;
_dirty[Register::SYN_FR_DIV_2] = 1;
/* flush to commit high FRDIV first, as low FRDIV commits the change */
flush();
_map.r.syn_int_div.SYN_INTDIV = div_q20 >> 20;
_dirty[Register::SYN_INT_DIV] = 1;
_map.r.syn_fr_div_2.SYN_FRDIV_19_10 = (div_q20 >> 10) & 0x3ff;
_dirty[Register::SYN_FR_DIV_2] = 1;
/* flush to commit high FRDIV first, as low FRDIV commits the change */
flush();
_map.r.syn_fr_div_1.SYN_FRDIV_9_0 = (div_q20 & 0x3ff);
_dirty[Register::SYN_FR_DIV_1] = 1;
flush();
_map.r.syn_fr_div_1.SYN_FRDIV_9_0 = (div_q20 & 0x3ff);
_dirty[Register::SYN_FR_DIV_1] = 1;
flush();
return true;
return true;
}
void MAX2837::set_rx_lo_iq_calibration(const size_t v) {
_map.r.rx_top_rx_bias.RX_IQERR_SPI_EN = 1;
_dirty[Register::RX_TOP_RX_BIAS] = 1;
_map.r.rxrf_2.iqerr_trim = v;
_dirty[Register::RXRF_2] = 1;
flush();
_map.r.rx_top_rx_bias.RX_IQERR_SPI_EN = 1;
_dirty[Register::RX_TOP_RX_BIAS] = 1;
_map.r.rxrf_2.iqerr_trim = v;
_dirty[Register::RXRF_2] = 1;
flush();
}
void MAX2837::set_rx_bias_trim(const size_t v) {
_map.r.rx_top_rx_bias.EN_Bias_Trim = 1;
_map.r.rx_top_rx_bias.BIAS_TRIM_SPI = v;
_dirty[Register::RX_TOP_RX_BIAS] = 1;
flush();
_map.r.rx_top_rx_bias.EN_Bias_Trim = 1;
_map.r.rx_top_rx_bias.BIAS_TRIM_SPI = v;
_dirty[Register::RX_TOP_RX_BIAS] = 1;
flush();
}
void MAX2837::set_vco_bias(const size_t v) {
_map.r.vco_cfg.VCO_BIAS_SPI_EN = 1;
_map.r.vco_cfg.VCO_BIAS_SPI = v;
_dirty[Register::VCO_CFG] = 1;
flush();
_map.r.vco_cfg.VCO_BIAS_SPI_EN = 1;
_map.r.vco_cfg.VCO_BIAS_SPI = v;
_dirty[Register::VCO_CFG] = 1;
flush();
}
void MAX2837::set_rx_buff_vcm(const size_t v) {
_map.r.lpf_3_vga_1.BUFF_VCM = v;
_dirty[Register::LPF_3_VGA_1] = 1;
flush();
_map.r.lpf_3_vga_1.BUFF_VCM = v;
_dirty[Register::LPF_3_VGA_1] = 1;
flush();
}
reg_t MAX2837::temp_sense() {
if( !_map.r.rx_top.ts_en ) {
_map.r.rx_top.ts_en = 1;
flush_one(Register::RX_TOP);
if (!_map.r.rx_top.ts_en) {
_map.r.rx_top.ts_en = 1;
flush_one(Register::RX_TOP);
chThdSleepMilliseconds(1);
}
chThdSleepMilliseconds(1);
}
_map.r.rx_top.ts_adc_trigger = 1;
flush_one(Register::RX_TOP);
_map.r.rx_top.ts_adc_trigger = 1;
flush_one(Register::RX_TOP);
halPolledDelay(ticks_for_temperature_sense_adc_conversion);
halPolledDelay(ticks_for_temperature_sense_adc_conversion);
const auto value = read(Register::TEMP_SENSE);
const auto value = read(Register::TEMP_SENSE);
_map.r.rx_top.ts_adc_trigger = 0;
flush_one(Register::RX_TOP);
_map.r.rx_top.ts_adc_trigger = 0;
flush_one(Register::RX_TOP);
return value;
return value;
}
}
} // namespace max2837

File diff suppressed because it is too large Load Diff

View File

@@ -37,14 +37,13 @@ namespace lna {
using namespace max283x::lna;
constexpr std::array<uint8_t, 8> lookup_8db_steps {
0b11, 0b11, 0b10, 0b10,
0b01, 0b00, 0b00, 0b00
};
constexpr std::array<uint8_t, 8> lookup_8db_steps{
0b11, 0b11, 0b10, 0b10,
0b01, 0b00, 0b00, 0b00};
static uint_fast8_t gain_ordinal(const int8_t db) {
const auto db_sat = gain_db_range.clip(db);
return lna::lookup_8db_steps[(db_sat >> 3) & 7];
const auto db_sat = gain_db_range.clip(db);
return lna::lookup_8db_steps[(db_sat >> 3) & 7];
}
} /* namespace lna */
@@ -53,11 +52,11 @@ namespace vga {
using namespace max283x::vga;
constexpr range_t<int8_t> gain_db_range_internal { 0, 63 };
constexpr range_t<int8_t> gain_db_range_internal{0, 63};
static uint_fast8_t gain_ordinal(const int8_t db) {
const auto db_sat = gain_db_range_internal.clip(db);
return (db_sat & 0b111111) ^ 0b111111;
const auto db_sat = gain_db_range_internal.clip(db);
return (db_sat & 0b111111) ^ 0b111111;
}
} /* namespace vga */
@@ -67,8 +66,8 @@ namespace tx {
using namespace max283x::tx;
static uint_fast8_t gain_ordinal(const int8_t db) {
const auto db_sat = gain_db_range.clip(db);
return 47 - db_sat;
const auto db_sat = gain_db_range.clip(db);
return 47 - db_sat;
}
} /* namespace tx */
@@ -78,10 +77,10 @@ namespace filter {
using namespace max283x::filter;
static uint_fast8_t bandwidth_ordinal(const uint32_t bandwidth) {
/* Determine filter setting that will provide bandwidth greater than or
* equal to requested bandwidth.
*/
return std::lower_bound(bandwidths.cbegin(), bandwidths.cend(), bandwidth) - bandwidths.cbegin();
/* Determine filter setting that will provide bandwidth greater than or
* equal to requested bandwidth.
*/
return std::lower_bound(bandwidths.cbegin(), bandwidths.cend(), bandwidth) - bandwidths.cbegin();
}
} /* namespace filter */
@@ -99,114 +98,118 @@ static int_fast8_t requested_rx_lna_gain = 0;
static int_fast8_t requested_rx_vga_gain = 0;
void MAX2839::init() {
set_mode(Mode::Shutdown);
set_mode(Mode::Shutdown);
gpio_max283x_enable.output();
gpio_max2839_rxtx.output();
gpio_max283x_enable.output();
gpio_max2839_rxtx.output();
_map.r.rxrf_1.MIMOmode = 1; /* enable RXINB */
_map.r.rxrf_1.MIMOmode = 1; /* enable RXINB */
_map.r.pa_drv.TXVGA_GAIN_SPI_EN = 1;
_map.r.tx_gain.TXVGA_GAIN_SPI = 0x00;
_map.r.pa_drv.TXVGA_GAIN_SPI_EN = 1;
_map.r.tx_gain.TXVGA_GAIN_SPI = 0x00;
_map.r.hpfsm_3.HPC_STOP = 1; /* 1kHz */
_map.r.hpfsm_3.HPC_STOP = 1; /* 1kHz */
_map.r.rxrf_2.LNAgain_SPI_EN = 1; /* control LNA gain from SPI */
_map.r.lpf_vga_1.L = 0b000;
_map.r.lpf_vga_2.L = 0b000;
_map.r.rxrf_2.LNAgain_SPI_EN = 1; /* control LNA gain from SPI */
_map.r.lpf_vga_1.L = 0b000;
_map.r.lpf_vga_2.L = 0b000;
_map.r.rx_top_1.VGAgain_SPI_EN = 1; /* control VGA gain from SPI */
_map.r.lpf_vga_1.VGA = 0b000000;
_map.r.lpf_vga_2.VGA = 0b010101;
_map.r.rx_top_1.VGAgain_SPI_EN = 1; /* control VGA gain from SPI */
_map.r.lpf_vga_1.VGA = 0b000000;
_map.r.lpf_vga_2.VGA = 0b010101;
_map.r.lpf_vga_2.BUFF_VCM = 0b11; /* maximum RX output common-mode voltage */
_map.r.lpf_vga_2.BUFF_VCM = 0b11; /* maximum RX output common-mode voltage */
_map.r.lpf_vga_1.ModeCtrl = 0b01; /* Rx LPF */
_map.r.lpf.FT = 0b0000; /* 1.75 MHz LPF */
_map.r.lpf_vga_1.ModeCtrl = 0b01; /* Rx LPF */
_map.r.lpf.FT = 0b0000; /* 1.75 MHz LPF */
_map.r.spi_en.EN_SPI = 1; /* enable chip functions when ENABLE pin set */
_map.r.spi_en.EN_SPI = 1; /* enable chip functions when ENABLE pin set */
_map.r.lo_gen.LOGEN_2GM = 0;
_map.r.lo_gen.LOGEN_2GM = 0;
_map.r.rssi_vga.RSSI_MODE = 1; /* RSSI independent of RXHP */
_map.r.rssi_vga.RSSI_MODE = 1; /* RSSI independent of RXHP */
/*
* 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.
*/
_map.r.rxrf_1.LNAband = 0; /* 2.3 - 2.5GHz */
/*
* 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.
*/
_map.r.rxrf_1.LNAband = 0; /* 2.3 - 2.5GHz */
_dirty.set();
flush();
_dirty.set();
flush();
set_mode(Mode::Standby);
set_mode(Mode::Standby);
}
enum class Mask {
Enable = 0b01,
RxTx = 0b10,
Shutdown = 0b00,
Standby = RxTx,
Receive = Enable | RxTx,
Transmit = Enable,
Enable = 0b01,
RxTx = 0b10,
Shutdown = 0b00,
Standby = RxTx,
Receive = Enable | RxTx,
Transmit = Enable,
};
Mask mode_mask(const Mode mode) {
switch (mode) {
case Mode::Standby: return Mask::Standby;
case Mode::Receive: return Mask::Receive;
case Mode::Transmit: return Mask::Transmit;
default: return Mask::Shutdown;
}
switch (mode) {
case Mode::Standby:
return Mask::Standby;
case Mode::Receive:
return Mask::Receive;
case Mode::Transmit:
return Mask::Transmit;
default:
return Mask::Shutdown;
}
}
void MAX2839::set_mode(const Mode mode) {
Mask mask = mode_mask(mode);
gpio_max283x_enable.write(toUType(mask) & toUType(Mask::Enable));
gpio_max2839_rxtx.write(toUType(mask) & toUType(Mask::RxTx));
Mask mask = mode_mask(mode);
gpio_max283x_enable.write(toUType(mask) & toUType(Mask::Enable));
gpio_max2839_rxtx.write(toUType(mask) & toUType(Mask::RxTx));
}
void MAX2839::flush() {
if( _dirty ) {
for(size_t n=0; n<reg_count; n++) {
if( _dirty[n] ) {
write(n, _map.w[n]);
}
}
_dirty.clear();
}
if (_dirty) {
for (size_t n = 0; n < reg_count; n++) {
if (_dirty[n]) {
write(n, _map.w[n]);
}
}
_dirty.clear();
}
}
void MAX2839::flush_one(const Register reg) {
const auto reg_num = toUType(reg);
write(reg_num, _map.w[reg_num]);
_dirty.clear(reg_num);
const auto reg_num = toUType(reg);
write(reg_num, _map.w[reg_num]);
_dirty.clear(reg_num);
}
void MAX2839::write(const address_t reg_num, const reg_t value) {
uint16_t t = (0U << 15) | (reg_num << 10) | (value & 0x3ffU);
_target.transfer(&t, 1);
uint16_t t = (0U << 15) | (reg_num << 10) | (value & 0x3ffU);
_target.transfer(&t, 1);
}
reg_t MAX2839::read(const address_t reg_num) {
uint16_t t = (1U << 15) | (reg_num << 10);
_target.transfer(&t, 1U);
return t & 0x3ffU;
uint16_t t = (1U << 15) | (reg_num << 10);
_target.transfer(&t, 1U);
return t & 0x3ffU;
}
void MAX2839::write(const Register reg, const reg_t value) {
write(toUType(reg), value);
write(toUType(reg), value);
}
reg_t MAX2839::read(const Register reg) {
return read(toUType(reg));
return read(toUType(reg));
}
void MAX2839::set_tx_vga_gain(const int_fast8_t db) {
_map.r.tx_gain.TXVGA_GAIN_SPI = tx::gain_ordinal(db);
_dirty[Register::TX_GAIN] = 1;
flush();
_map.r.tx_gain.TXVGA_GAIN_SPI = tx::gain_ordinal(db);
_dirty[Register::TX_GAIN] = 1;
flush();
}
/*
@@ -215,140 +218,140 @@ void MAX2839::set_tx_vga_gain(const int_fast8_t db) {
* user experience.
*/
void MAX2839::configure_rx_gain() {
/* Apply MAX2837 restrictions to requested gain settings. */
int_fast8_t lna_gain = lna::gain_db_range.clip(requested_rx_lna_gain);
lna_gain &= 0x38;
int_fast8_t vga_gain = vga::gain_db_range.clip(requested_rx_vga_gain);
vga_gain &= 0x3e;
/* Apply MAX2837 restrictions to requested gain settings. */
int_fast8_t lna_gain = lna::gain_db_range.clip(requested_rx_lna_gain);
lna_gain &= 0x38;
int_fast8_t vga_gain = vga::gain_db_range.clip(requested_rx_vga_gain);
vga_gain &= 0x3e;
/*
* MAX2839 has lower full-scale RX output voltage than MAX2837, so we
* adjust the VGA (baseband) gain to compensate.
*/
vga_gain += 3;
/*
* MAX2839 has lower full-scale RX output voltage than MAX2837, so we
* adjust the VGA (baseband) gain to compensate.
*/
vga_gain += 3;
/*
* 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;
}
}
/*
* 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 (16 dB) and max-40 dB (0 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;
}
}
/*
* MAX2839 lacks max-24 dB (16 dB) and max-40 dB (0 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;
}
}
_map.r.lpf_vga_2.L = lna::gain_ordinal(lna_gain);
_dirty[Register::RXRF_2] = 1;
_map.r.lpf_vga_2.VGA = vga::gain_ordinal(vga_gain);
_dirty[Register::LPF_VGA_2] = 1;
flush();
_map.r.lpf_vga_2.L = lna::gain_ordinal(lna_gain);
_dirty[Register::RXRF_2] = 1;
_map.r.lpf_vga_2.VGA = vga::gain_ordinal(vga_gain);
_dirty[Register::LPF_VGA_2] = 1;
flush();
}
void MAX2839::set_lna_gain(const int_fast8_t db) {
requested_rx_lna_gain = db;
configure_rx_gain();
requested_rx_lna_gain = db;
configure_rx_gain();
}
void MAX2839::set_vga_gain(const int_fast8_t db) {
requested_rx_vga_gain = db;
configure_rx_gain();
requested_rx_vga_gain = db;
configure_rx_gain();
}
void MAX2839::set_lpf_rf_bandwidth(const uint32_t bandwidth_minimum) {
_map.r.lpf.FT = filter::bandwidth_ordinal(bandwidth_minimum);
_dirty[Register::LPF] = 1;
flush();
_map.r.lpf.FT = filter::bandwidth_ordinal(bandwidth_minimum);
_dirty[Register::LPF] = 1;
flush();
}
bool MAX2839::set_frequency(const rf::Frequency lo_frequency) {
/* TODO: This is a sad implementation. Refactor. */
if( lo::band[0].contains(lo_frequency) ) {
_map.r.syn_int_div.LOGEN_BSW = 0b00; /* 2300 - 2399.99MHz */
} else if( lo::band[1].contains(lo_frequency) ) {
_map.r.syn_int_div.LOGEN_BSW = 0b01; /* 2400 - 2499.99MHz */
} else if( lo::band[2].contains(lo_frequency) ) {
_map.r.syn_int_div.LOGEN_BSW = 0b10; /* 2500 - 2599.99MHz */
} else if( lo::band[3].contains(lo_frequency) ) {
_map.r.syn_int_div.LOGEN_BSW = 0b11; /* 2600 - 2700Hz */
} else {
return false;
}
_dirty[Register::SYN_INT_DIV] = 1;
/* TODO: This is a sad implementation. Refactor. */
if (lo::band[0].contains(lo_frequency)) {
_map.r.syn_int_div.LOGEN_BSW = 0b00; /* 2300 - 2399.99MHz */
} else if (lo::band[1].contains(lo_frequency)) {
_map.r.syn_int_div.LOGEN_BSW = 0b01; /* 2400 - 2499.99MHz */
} else if (lo::band[2].contains(lo_frequency)) {
_map.r.syn_int_div.LOGEN_BSW = 0b10; /* 2500 - 2599.99MHz */
} else if (lo::band[3].contains(lo_frequency)) {
_map.r.syn_int_div.LOGEN_BSW = 0b11; /* 2600 - 2700Hz */
} else {
return false;
}
_dirty[Register::SYN_INT_DIV] = 1;
const uint64_t div_q20 = (lo_frequency * (1 << 20)) / pll_factor;
const uint64_t div_q20 = (lo_frequency * (1 << 20)) / pll_factor;
_map.r.syn_int_div.SYN_INTDIV = div_q20 >> 20;
_dirty[Register::SYN_INT_DIV] = 1;
_map.r.syn_fr_div_2.SYN_FRDIV_19_10 = (div_q20 >> 10) & 0x3ff;
_dirty[Register::SYN_FR_DIV_2] = 1;
/* flush to commit high FRDIV first, as low FRDIV commits the change */
flush();
_map.r.syn_int_div.SYN_INTDIV = div_q20 >> 20;
_dirty[Register::SYN_INT_DIV] = 1;
_map.r.syn_fr_div_2.SYN_FRDIV_19_10 = (div_q20 >> 10) & 0x3ff;
_dirty[Register::SYN_FR_DIV_2] = 1;
/* flush to commit high FRDIV first, as low FRDIV commits the change */
flush();
_map.r.syn_fr_div_1.SYN_FRDIV_9_0 = (div_q20 & 0x3ff);
_dirty[Register::SYN_FR_DIV_1] = 1;
flush();
_map.r.syn_fr_div_1.SYN_FRDIV_9_0 = (div_q20 & 0x3ff);
_dirty[Register::SYN_FR_DIV_1] = 1;
flush();
return true;
return true;
}
void MAX2839::set_rx_lo_iq_calibration(const size_t v) {
_map.r.rxrf_2.RX_IQERR_SPI_EN = 1;
_dirty[Register::RXRF_2] = 1;
_map.r.rxrf_1.iqerr_trim = v;
_dirty[Register::RXRF_1] = 1;
flush();
_map.r.rxrf_2.RX_IQERR_SPI_EN = 1;
_dirty[Register::RXRF_2] = 1;
_map.r.rxrf_1.iqerr_trim = v;
_dirty[Register::RXRF_1] = 1;
flush();
}
void MAX2839::set_rx_buff_vcm(const size_t v) {
_map.r.lpf_vga_2.BUFF_VCM = v;
_dirty[Register::LPF_VGA_2] = 1;
flush();
_map.r.lpf_vga_2.BUFF_VCM = v;
_dirty[Register::LPF_VGA_2] = 1;
flush();
}
reg_t MAX2839::temp_sense() {
if( !_map.r.rx_top_2.ts_en ) {
_map.r.rx_top_2.ts_en = 1;
flush_one(Register::RX_TOP_2);
if (!_map.r.rx_top_2.ts_en) {
_map.r.rx_top_2.ts_en = 1;
flush_one(Register::RX_TOP_2);
chThdSleepMilliseconds(1);
}
chThdSleepMilliseconds(1);
}
_map.r.rx_top_2.ts_adc_trigger = 1;
flush_one(Register::RX_TOP_2);
_map.r.rx_top_2.ts_adc_trigger = 1;
flush_one(Register::RX_TOP_2);
halPolledDelay(ticks_for_temperature_sense_adc_conversion);
halPolledDelay(ticks_for_temperature_sense_adc_conversion);
/*
* Things look very similar to MAX2837, so this probably works, but the
* MAX2839 data sheet does not describe the TEMP_SENSE register contents.
*/
const auto value = read(Register::TEMP_SENSE);
/*
* Things look very similar to MAX2837, so this probably works, but the
* MAX2839 data sheet does not describe the TEMP_SENSE register contents.
*/
const auto value = read(Register::TEMP_SENSE);
_map.r.rx_top_2.ts_adc_trigger = 0;
flush_one(Register::RX_TOP_2);
_map.r.rx_top_2.ts_adc_trigger = 0;
flush_one(Register::RX_TOP_2);
return value;
return value;
}
}
} // namespace max2839

File diff suppressed because it is too large Load Diff

View File

@@ -30,12 +30,12 @@ namespace max283x {
namespace lo {
constexpr std::array<rf::FrequencyRange, 4> band { {
{ 2300000000, 2400000000 },
{ 2400000000, 2500000000 },
{ 2500000000, 2600000000 },
{ 2600000000, 2700000000 },
} };
constexpr std::array<rf::FrequencyRange, 4> band{{
{2300000000, 2400000000},
{2400000000, 2500000000},
{2500000000, 2600000000},
{2600000000, 2700000000},
}};
} /* namespace lo */
@@ -43,13 +43,13 @@ constexpr std::array<rf::FrequencyRange, 4> band { {
namespace lna {
constexpr range_t<int8_t> gain_db_range { 0, 40 };
constexpr range_t<int8_t> gain_db_range{0, 40};
constexpr int8_t gain_db_step = 8;
constexpr std::array<rf::FrequencyRange, 2> band { {
{ 2300000000, 2500000000 },
{ 2500000000, 2700000000 },
} };
constexpr std::array<rf::FrequencyRange, 2> band{{
{2300000000, 2500000000},
{2500000000, 2700000000},
}};
} /* namespace lna */
@@ -57,7 +57,7 @@ constexpr std::array<rf::FrequencyRange, 2> band { {
namespace vga {
constexpr range_t<int8_t> gain_db_range { 0, 62 };
constexpr range_t<int8_t> gain_db_range{0, 62};
constexpr int8_t gain_db_step = 2;
} /* namespace vga */
@@ -66,32 +66,32 @@ constexpr int8_t gain_db_step = 2;
namespace tx {
constexpr range_t<int8_t> gain_db_range { 0, 47 };
constexpr range_t<int8_t> gain_db_range{0, 47};
constexpr int8_t gain_db_step = 1;
}
} // namespace tx
/*************************************************************************/
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 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];
@@ -102,37 +102,37 @@ constexpr auto bandwidth_maximum = bandwidths[bandwidths.size() - 1];
/*************************************************************************/
enum Mode {
Shutdown,
Standby,
Receive,
Transmit,
Shutdown,
Standby,
Receive,
Transmit,
};
using reg_t = uint16_t;
using address_t = uint8_t;
class MAX283x {
public:
virtual ~MAX283x() = default;
public:
virtual ~MAX283x() = default;
virtual void init();
virtual void set_mode(const Mode mode);
virtual void init();
virtual void set_mode(const Mode mode);
virtual void set_tx_vga_gain(const int_fast8_t db);
virtual void set_lna_gain(const int_fast8_t db);
virtual void set_vga_gain(const int_fast8_t db);
virtual void set_lpf_rf_bandwidth(const uint32_t bandwidth_minimum);
virtual void set_tx_vga_gain(const int_fast8_t db);
virtual void set_lna_gain(const int_fast8_t db);
virtual void set_vga_gain(const int_fast8_t db);
virtual void set_lpf_rf_bandwidth(const uint32_t bandwidth_minimum);
virtual bool set_frequency(const rf::Frequency lo_frequency);
virtual bool set_frequency(const rf::Frequency lo_frequency);
virtual void set_rx_lo_iq_calibration(const size_t v);
virtual void set_rx_buff_vcm(const size_t v);
virtual void set_rx_lo_iq_calibration(const size_t v);
virtual void set_rx_buff_vcm(const size_t v);
virtual reg_t temp_sense();
virtual reg_t temp_sense();
virtual reg_t read(const address_t reg_num);
virtual reg_t read(const address_t reg_num);
};
}
} // namespace max283x
#endif/*__MAX283X_H__*/
#endif /*__MAX283X_H__*/

View File

@@ -29,8 +29,8 @@
namespace max5864 {
void MAX5864::set_mode(const Mode mode) {
std::array<uint8_t, 1> command { toUType(mode) };
_target.transfer(command.data(), command.size());
std::array<uint8_t, 1> command{toUType(mode)};
_target.transfer(command.data(), command.size());
}
}
} // namespace max5864

View File

@@ -27,33 +27,32 @@
namespace max5864 {
enum class Mode : uint8_t {
Shutdown = 0x00,
Idle = 0x01,
Receive = 0x02,
Transmit = 0x03,
Transceiver = 0x04,
Standby = 0x05,
Shutdown = 0x00,
Idle = 0x01,
Receive = 0x02,
Transmit = 0x03,
Transceiver = 0x04,
Standby = 0x05,
};
class MAX5864 {
public:
constexpr MAX5864(
spi::arbiter::Target& target
) : _target(target)
{
}
public:
constexpr MAX5864(
spi::arbiter::Target& target)
: _target(target) {
}
void init() {
/* Shut down explicitly, as there is no other reset mechanism. */
set_mode(Mode::Shutdown);
}
void init() {
/* Shut down explicitly, as there is no other reset mechanism. */
set_mode(Mode::Shutdown);
}
void set_mode(const Mode mode);
void set_mode(const Mode mode);
private:
spi::arbiter::Target& _target;
private:
spi::arbiter::Target& _target;
};
}
} // namespace max5864
#endif/*__MAX5864_H__*/
#endif /*__MAX5864_H__*/

View File

@@ -51,7 +51,7 @@ constexpr auto reference_frequency = rffc5072_reference_f;
namespace vco {
constexpr rf::FrequencyRange range { 2700000000, 5400000000 };
constexpr rf::FrequencyRange range{2700000000, 5400000000};
} /* namespace vco */
@@ -63,24 +63,24 @@ constexpr size_t divider_log2_max = 5;
constexpr size_t divider_min = 1U << divider_log2_min;
constexpr size_t divider_max = 1U << divider_log2_max;
constexpr rf::FrequencyRange range { vco::range.minimum / divider_max, vco::range.maximum / divider_min };
constexpr rf::FrequencyRange range{vco::range.minimum / divider_max, vco::range.maximum / divider_min};
size_t divider_log2(const rf::Frequency lo_frequency) {
/* TODO: Error */
/*
if( lo::range.out_of_range(lo_frequency) ) {
return;
}
*/
/* Compute LO divider. */
auto lo_divider_log2 = lo::divider_log2_min;
auto vco_frequency = lo_frequency;
while( vco::range.below_range(vco_frequency) ) {
vco_frequency <<= 1;
lo_divider_log2 += 1;
}
/* TODO: Error */
/*
if( lo::range.out_of_range(lo_frequency) ) {
return;
}
*/
/* Compute LO divider. */
auto lo_divider_log2 = lo::divider_log2_min;
auto vco_frequency = lo_frequency;
while (vco::range.below_range(vco_frequency)) {
vco_frequency <<= 1;
lo_divider_log2 += 1;
}
return lo_divider_log2;
return lo_divider_log2;
}
} /* namespace lo */
@@ -96,42 +96,40 @@ constexpr size_t divider_min = 1U << divider_log2_min;
constexpr size_t divider_max = 1U << divider_log2_max;
constexpr size_t divider_log2(const rf::Frequency vco_frequency) {
return (vco_frequency > (prescaler::divider_min * prescaler::max_frequency))
? prescaler::divider_log2_max
: prescaler::divider_log2_min
;
return (vco_frequency > (prescaler::divider_min * prescaler::max_frequency))
? prescaler::divider_log2_max
: prescaler::divider_log2_min;
}
} /* namespace prescaler */
struct SynthConfig {
const size_t lo_divider_log2;
const size_t prescaler_divider_log2;
const uint64_t n_divider_q24;
const size_t lo_divider_log2;
const size_t prescaler_divider_log2;
const uint64_t n_divider_q24;
static SynthConfig calculate(
const rf::Frequency lo_frequency
) {
/* RFFC507x frequency synthesizer is is accurate to about 2ppb (two parts
* per BILLION). There's not much point to worrying about rounding and
* tuning error, when it amounts to 8Hz at 5GHz!
*/
const size_t lo_divider_log2 = lo::divider_log2(lo_frequency);
const size_t lo_divider = 1U << lo_divider_log2;
static SynthConfig calculate(
const rf::Frequency lo_frequency) {
/* RFFC507x frequency synthesizer is is accurate to about 2ppb (two parts
* per BILLION). There's not much point to worrying about rounding and
* tuning error, when it amounts to 8Hz at 5GHz!
*/
const size_t lo_divider_log2 = lo::divider_log2(lo_frequency);
const size_t lo_divider = 1U << lo_divider_log2;
const rf::Frequency vco_frequency = lo_frequency * lo_divider;
const rf::Frequency vco_frequency = lo_frequency * lo_divider;
const size_t prescaler_divider_log2 = prescaler::divider_log2(vco_frequency);
const size_t prescaler_divider_log2 = prescaler::divider_log2(vco_frequency);
const uint64_t prescaled_lo_q24 = vco_frequency << (24 - prescaler_divider_log2);
const uint64_t n_divider_q24 = prescaled_lo_q24 / reference_frequency;
const uint64_t prescaled_lo_q24 = vco_frequency << (24 - prescaler_divider_log2);
const uint64_t n_divider_q24 = prescaled_lo_q24 / reference_frequency;
return {
lo_divider_log2,
prescaler_divider_log2,
n_divider_q24,
};
}
return {
lo_divider_log2,
prescaler_divider_log2,
n_divider_q24,
};
}
};
/* Readback values, RFFC5072 rev A:
@@ -146,136 +144,136 @@ struct SynthConfig {
*/
void RFFC507x::init() {
gpio_rffc5072_resetx.set();
gpio_rffc5072_resetx.output();
reset();
gpio_rffc5072_resetx.set();
gpio_rffc5072_resetx.output();
reset();
_bus.init();
_bus.init();
_dirty.set();
flush();
_dirty.set();
flush();
}
void RFFC507x::reset() {
/* TODO: Is RESETB pin ignored if sdi_ctrl.sipin=1? Programming guide
* description of sdi_ctrl.sipin suggests the pin is not ignored.
*/
gpio_rffc5072_resetx.clear();
halPolledDelay(ticks_during_reset);
gpio_rffc5072_resetx.set();
halPolledDelay(ticks_after_reset);
/* TODO: Is RESETB pin ignored if sdi_ctrl.sipin=1? Programming guide
* description of sdi_ctrl.sipin suggests the pin is not ignored.
*/
gpio_rffc5072_resetx.clear();
halPolledDelay(ticks_during_reset);
gpio_rffc5072_resetx.set();
halPolledDelay(ticks_after_reset);
}
void RFFC507x::flush() {
if( _dirty ) {
for(size_t i=0; i<_map.w.size(); i++) {
if( _dirty[i] ) {
write(i, _map.w[i]);
}
}
_dirty.clear();
}
if (_dirty) {
for (size_t i = 0; i < _map.w.size(); i++) {
if (_dirty[i]) {
write(i, _map.w[i]);
}
}
_dirty.clear();
}
}
void RFFC507x::write(const address_t reg_num, const spi::reg_t value) {
_bus.write(reg_num, value);
_bus.write(reg_num, value);
}
spi::reg_t RFFC507x::read(const address_t reg_num) {
return _bus.read(reg_num);
return _bus.read(reg_num);
}
void RFFC507x::write(const Register reg, const spi::reg_t value) {
write(toUType(reg), value);
write(toUType(reg), value);
}
spi::reg_t RFFC507x::read(const Register reg) {
return read(toUType(reg));
return read(toUType(reg));
}
void RFFC507x::flush_one(const Register reg) {
const auto reg_num = toUType(reg);
write(reg_num, _map.w[reg_num]);
_dirty.clear(reg_num);
const auto reg_num = toUType(reg);
write(reg_num, _map.w[reg_num]);
_dirty.clear(reg_num);
}
void RFFC507x::enable() {
_map.r.sdi_ctrl.enbl = 1;
flush_one(Register::SDI_CTRL);
_map.r.sdi_ctrl.enbl = 1;
flush_one(Register::SDI_CTRL);
/* TODO: Reset PLLCPL after CT_CAL? */
/* TODO: Reset PLLCPL after CT_CAL? */
/* TODO: After device is enabled and CT_cal is complete and VCO > 3.2GHz,
* change prescaler divider to 2, update synthesizer ratio, change
* lf.pllcpl from 3 to 2.
*/
/* TODO: After device is enabled and CT_cal is complete and VCO > 3.2GHz,
* change prescaler divider to 2, update synthesizer ratio, change
* lf.pllcpl from 3 to 2.
*/
}
void RFFC507x::disable() {
_map.r.sdi_ctrl.enbl = 0;
flush_one(Register::SDI_CTRL);
_map.r.sdi_ctrl.enbl = 0;
flush_one(Register::SDI_CTRL);
}
void RFFC507x::set_mixer_current(const uint8_t value) {
/* MIX IDD = 0b000 appears to turn the mixer completely off */
/* TODO: Adjust mixer current. Graphs in datasheet suggest:
* MIX_IDD=1 has lowest noise figure (10.1dB vs 13dB @ MIX_IDD=7).
* MIX_IDD=5 has highest IP3 (24dBm vs 10.3dBm @ MIX_IDD=1).
* MIX_IDD=5 has highest P1dB (11.8dBm vs 1.5dBm @ MIX_IDD=1).
* Mixer input impedance ~85 Ohms at MIX_IDD=4.
* Mixer input impedance inversely proportional to MIX_IDD.
* Balun balanced (mixer) side is 100 Ohms. Perhaps reduce MIX_IDD
* a bit to get 100 Ohms from mixer.
*/
_map.r.mix_cont.p1mixidd = value;
_map.r.mix_cont.p2mixidd = value;
flush_one(Register::MIX_CONT);
/* MIX IDD = 0b000 appears to turn the mixer completely off */
/* TODO: Adjust mixer current. Graphs in datasheet suggest:
* MIX_IDD=1 has lowest noise figure (10.1dB vs 13dB @ MIX_IDD=7).
* MIX_IDD=5 has highest IP3 (24dBm vs 10.3dBm @ MIX_IDD=1).
* MIX_IDD=5 has highest P1dB (11.8dBm vs 1.5dBm @ MIX_IDD=1).
* Mixer input impedance ~85 Ohms at MIX_IDD=4.
* Mixer input impedance inversely proportional to MIX_IDD.
* Balun balanced (mixer) side is 100 Ohms. Perhaps reduce MIX_IDD
* a bit to get 100 Ohms from mixer.
*/
_map.r.mix_cont.p1mixidd = value;
_map.r.mix_cont.p2mixidd = value;
flush_one(Register::MIX_CONT);
}
void RFFC507x::set_frequency(const rf::Frequency lo_frequency) {
const SynthConfig synth_config = SynthConfig::calculate(lo_frequency);
const SynthConfig synth_config = SynthConfig::calculate(lo_frequency);
/* Boost charge pump leakage if VCO frequency > 3.2GHz, indicated by
* prescaler divider set to 4 (log2=2) instead of 2 (log2=1).
*/
if( synth_config.prescaler_divider_log2 == 2 ) {
_map.r.lf.pllcpl = 3;
} else {
_map.r.lf.pllcpl = 2;
}
flush_one(Register::LF);
/* Boost charge pump leakage if VCO frequency > 3.2GHz, indicated by
* prescaler divider set to 4 (log2=2) instead of 2 (log2=1).
*/
if (synth_config.prescaler_divider_log2 == 2) {
_map.r.lf.pllcpl = 3;
} else {
_map.r.lf.pllcpl = 2;
}
flush_one(Register::LF);
_map.r.p2_freq1.p2n = synth_config.n_divider_q24 >> 24;
_map.r.p2_freq1.p2lodiv = synth_config.lo_divider_log2;
_map.r.p2_freq1.p2presc = synth_config.prescaler_divider_log2;
_map.r.p2_freq2.p2nmsb = (synth_config.n_divider_q24 >> 8) & 0xffff;
_map.r.p2_freq3.p2nlsb = synth_config.n_divider_q24 & 0xff;
_dirty[Register::P2_FREQ1] = 1;
_dirty[Register::P2_FREQ2] = 1;
_dirty[Register::P2_FREQ3] = 1;
flush();
_map.r.p2_freq1.p2n = synth_config.n_divider_q24 >> 24;
_map.r.p2_freq1.p2lodiv = synth_config.lo_divider_log2;
_map.r.p2_freq1.p2presc = synth_config.prescaler_divider_log2;
_map.r.p2_freq2.p2nmsb = (synth_config.n_divider_q24 >> 8) & 0xffff;
_map.r.p2_freq3.p2nlsb = synth_config.n_divider_q24 & 0xff;
_dirty[Register::P2_FREQ1] = 1;
_dirty[Register::P2_FREQ2] = 1;
_dirty[Register::P2_FREQ3] = 1;
flush();
}
void RFFC507x::set_gpo1(const bool new_value) {
if( new_value ) {
_map.r.gpo.p2gpo |= 1;
_map.r.gpo.p1gpo |= 1;
} else {
_map.r.gpo.p2gpo &= ~1;
_map.r.gpo.p1gpo &= ~1;
}
if (new_value) {
_map.r.gpo.p2gpo |= 1;
_map.r.gpo.p1gpo |= 1;
} else {
_map.r.gpo.p2gpo &= ~1;
_map.r.gpo.p1gpo &= ~1;
}
flush_one(Register::GPO);
flush_one(Register::GPO);
}
spi::reg_t RFFC507x::readback(const Readback readback) {
/* TODO: This clobbers the rest of the DEV_CTRL register
* Time to implement bitfields for registers.
*/
_map.r.dev_ctrl.readsel = toUType(readback);
flush_one(Register::DEV_CTRL);
/* TODO: This clobbers the rest of the DEV_CTRL register
* Time to implement bitfields for registers.
*/
_map.r.dev_ctrl.readsel = toUType(readback);
flush_one(Register::DEV_CTRL);
return read(Register::READBACK);
return read(Register::READBACK);
}
} /* namespace rffc507x */

File diff suppressed because it is too large Load Diff

View File

@@ -30,80 +30,78 @@ namespace rffc507x {
namespace spi {
void SPI::init() {
gpio_rffc5072_select.set();
gpio_rffc5072_clock.clear();
gpio_rffc5072_select.set();
gpio_rffc5072_clock.clear();
gpio_rffc5072_select.output();
gpio_rffc5072_clock.output();
gpio_rffc5072_data.input();
gpio_rffc5072_select.output();
gpio_rffc5072_clock.output();
gpio_rffc5072_data.input();
gpio_rffc5072_data.clear();
gpio_rffc5072_data.clear();
}
inline void SPI::select(const bool active) {
gpio_rffc5072_select.write(!active);
gpio_rffc5072_select.write(!active);
}
inline void SPI::direction_out() {
gpio_rffc5072_data.output();
gpio_rffc5072_data.output();
}
inline void SPI::direction_in() {
gpio_rffc5072_data.input();
gpio_rffc5072_data.input();
}
inline void SPI::write_bit(const bit_t value) {
gpio_rffc5072_data.write(value);
gpio_rffc5072_data.write(value);
}
inline bit_t SPI::read_bit() {
return gpio_rffc5072_data.read() & 1;
return gpio_rffc5072_data.read() & 1;
}
inline bit_t SPI::transfer_bit(const bit_t bit_out) {
gpio_rffc5072_clock.clear();
write_bit(bit_out);
const bit_t bit_in = read_bit();
gpio_rffc5072_clock.set();
return bit_in;
gpio_rffc5072_clock.clear();
write_bit(bit_out);
const bit_t bit_in = read_bit();
gpio_rffc5072_clock.set();
return bit_in;
}
data_t SPI::transfer_bits(const data_t data_out, const size_t count) {
data_t data_in = 0;
for(size_t i=0; i<count; i++) {
data_in = (data_in << 1) | transfer_bit((data_out >> (count - i - 1)) & 1);
}
return data_in;
data_t data_in = 0;
for (size_t i = 0; i < count; i++) {
data_in = (data_in << 1) | transfer_bit((data_out >> (count - i - 1)) & 1);
}
return data_in;
}
data_t SPI::transfer_word(const Direction direction, const address_t address, const data_t data_out) {
select(true);
select(true);
const data_t address_word =
((direction == Direction::Read) ? (1 << 7) : 0)
| (address & 0x7f)
;
const data_t address_word =
((direction == Direction::Read) ? (1 << 7) : 0) | (address & 0x7f);
direction_out();
transfer_bits(address_word, 9);
direction_out();
transfer_bits(address_word, 9);
if( direction == Direction::Read ) {
direction_in();
transfer_bits(0, 2);
}
if (direction == Direction::Read) {
direction_in();
transfer_bits(0, 2);
}
const data_t data_in = transfer_bits(data_out, 16);
const data_t data_in = transfer_bits(data_out, 16);
if( direction == Direction::Write ) {
direction_in();
}
if (direction == Direction::Write) {
direction_in();
}
select(false);
select(false);
transfer_bits(0, 2);
transfer_bits(0, 2);
return data_in;
return data_in;
}
}
}
} // namespace spi
} // namespace rffc507x

View File

@@ -34,37 +34,37 @@ using bit_t = uint_fast8_t;
using data_t = uint32_t;
class SPI {
public:
enum class Direction {
Write = 0,
Read = 1,
};
public:
enum class Direction {
Write = 0,
Read = 1,
};
void init();
void init();
reg_t read(const address_t address) {
return transfer_word(Direction::Read, address, 0);
}
reg_t read(const address_t address) {
return transfer_word(Direction::Read, address, 0);
}
void write(const address_t address, const reg_t value) {
transfer_word(Direction::Write, address, value);
}
void write(const address_t address, const reg_t value) {
transfer_word(Direction::Write, address, value);
}
private:
void select(const bool active);
private:
void select(const bool active);
void direction_out();
void direction_in();
void direction_out();
void direction_in();
void write_bit(const bit_t value);
bit_t read_bit();
void write_bit(const bit_t value);
bit_t read_bit();
bit_t transfer_bit(const bit_t bit_out);
data_t transfer_bits(const data_t data_out, const size_t count);
data_t transfer_word(const Direction direction, const address_t address, const data_t data_out);
bit_t transfer_bit(const bit_t bit_out);
data_t transfer_bits(const data_t data_out, const size_t count);
data_t transfer_word(const Direction direction, const address_t address, const data_t data_out);
};
} /* spi */
} /* rffc507x */
} // namespace spi
} // namespace rffc507x
#endif/*__RFFC507X_SPI_H__*/
#endif /*__RFFC507X_SPI_H__*/

View File

@@ -29,77 +29,71 @@
namespace si5351 {
void Si5351::reset() {
wait_for_device_ready();
wait_for_device_ready();
write_register(Register::InterruptStatusSticky, 0x00);
write_register(Register::InterruptStatusMask, 0xf0);
write_register(Register::InterruptStatusSticky, 0x00);
write_register(Register::InterruptStatusMask, 0xf0);
disable_output_mask(0xff);
write_register(Register::OEBPinEnableControlMask, 0xff);
write_register(Register::PLLInputSource, 0x00);
disable_output_mask(0xff);
write_register(Register::OEBPinEnableControlMask, 0xff);
write_register(Register::PLLInputSource, 0x00);
set_clock_control({
ClockControl::power_off(), ClockControl::power_off(),
ClockControl::power_off(), ClockControl::power_off(),
ClockControl::power_off(), ClockControl::power_off(),
ClockControl::power_off(), ClockControl::power_off()
});
set_clock_control({ClockControl::power_off(), ClockControl::power_off(),
ClockControl::power_off(), ClockControl::power_off(),
ClockControl::power_off(), ClockControl::power_off(),
ClockControl::power_off(), ClockControl::power_off()});
write(std::array<uint8_t, 70> { Register::CLK3_0DisableState });
write(std::array<uint8_t, 70>{Register::CLK3_0DisableState});
write(std::array<uint8_t, 14>{
Register::SpreadSpectrumParameters_Base
});
write(std::array<uint8_t, 14>{
Register::SpreadSpectrumParameters_Base});
write(std::array<uint8_t, 4>{
Register::VCXOParameters_Base
});
write(std::array<uint8_t, 4>{
Register::VCXOParameters_Base});
write(std::array<uint8_t, 7>{
Register::CLKInitialPhaseOffset_Base
});
write(std::array<uint8_t, 7>{
Register::CLKInitialPhaseOffset_Base});
write_register(Register::CrystalInternalLoadCapacitance, 0b11010010);
write_register(Register::FanoutEnable, 0x00);
write_register(Register::CrystalInternalLoadCapacitance, 0b11010010);
write_register(Register::FanoutEnable, 0x00);
reset_plls();
reset_plls();
}
Si5351::regvalue_t Si5351::read_register(const uint8_t reg) {
const std::array<uint8_t, 1> tx { reg };
std::array<uint8_t, 1> rx { 0x00 };
_bus.transmit(_address, tx.data(), tx.size());
_bus.receive(_address, rx.data(), rx.size());
return rx[0];
const std::array<uint8_t, 1> tx{reg};
std::array<uint8_t, 1> rx{0x00};
_bus.transmit(_address, tx.data(), tx.size());
_bus.receive(_address, rx.data(), rx.size());
return rx[0];
}
void Si5351::set_ms_frequency(
const size_t ms_number,
const uint32_t frequency,
const uint32_t vco_frequency,
const size_t r_div
) {
/* TODO: Factor out the VCO frequency, which should be an attribute held
* by the Si5351 object.
*/
const uint32_t a = vco_frequency / frequency;
const uint32_t remainder = vco_frequency - (frequency * a);
const uint32_t denom = gcd(remainder, frequency);
const uint32_t b = remainder / denom;
const uint32_t c = frequency / denom;
const size_t ms_number,
const uint32_t frequency,
const uint32_t vco_frequency,
const size_t r_div) {
/* TODO: Factor out the VCO frequency, which should be an attribute held
* by the Si5351 object.
*/
const uint32_t a = vco_frequency / frequency;
const uint32_t remainder = vco_frequency - (frequency * a);
const uint32_t denom = gcd(remainder, frequency);
const uint32_t b = remainder / denom;
const uint32_t c = frequency / denom;
/* TODO: Switch between integer and fractional modes depending on the
* values of a and b.
*/
const MultisynthFractional ms {
.f_src = vco_frequency,
.a = a,
.b = b,
.c = c,
.r_div = r_div,
};
const auto regs = ms.reg(ms_number);
write(regs);
/* TODO: Switch between integer and fractional modes depending on the
* values of a and b.
*/
const MultisynthFractional ms{
.f_src = vco_frequency,
.a = a,
.b = b,
.c = c,
.r_div = r_div,
};
const auto regs = ms.reg(ms_number);
write(regs);
}
} /* namespace si5351 */

View File

@@ -36,158 +36,157 @@ namespace si5351 {
using reg_t = uint8_t;
namespace Register {
enum {
DeviceStatus = 0,
InterruptStatusSticky = 1,
InterruptStatusMask = 2,
OutputEnableControl = 3,
OEBPinEnableControlMask = 9,
PLLInputSource = 15,
CLKControl_Base = 16,
CLKControl0 = 16,
CLKControl1 = 17,
CLKControl2 = 18,
CLKControl3 = 19,
CLKControl4 = 20,
CLKControl5 = 21,
CLKControl6 = 22,
CLKControl7 = 23,
CLK3_0DisableState = 24,
CLK7_4DisableState = 25,
MultisynthNAParameters_Base = 26,
MultisynthNBParameters_Base = 34,
Multisynth0Parameters_Base = 42,
Multisynth1Parameters_Base = 50,
Multisynth2Parameters_Base = 58,
Multisynth3Parameters_Base = 66,
Multisynth4Parameters_Base = 74,
Multisynth5Parameters_Base = 82,
Multisynth6Parameters = 90,
Multisynth7Parameters = 91,
Clock6And7OutputDivider = 92,
SpreadSpectrumParameters_Base = 149,
VCXOParameters_Base = 162,
CLKInitialPhaseOffset_Base = 165,
PLLReset = 177,
CrystalInternalLoadCapacitance = 183,
FanoutEnable = 187,
};
enum {
DeviceStatus = 0,
InterruptStatusSticky = 1,
InterruptStatusMask = 2,
OutputEnableControl = 3,
OEBPinEnableControlMask = 9,
PLLInputSource = 15,
CLKControl_Base = 16,
CLKControl0 = 16,
CLKControl1 = 17,
CLKControl2 = 18,
CLKControl3 = 19,
CLKControl4 = 20,
CLKControl5 = 21,
CLKControl6 = 22,
CLKControl7 = 23,
CLK3_0DisableState = 24,
CLK7_4DisableState = 25,
MultisynthNAParameters_Base = 26,
MultisynthNBParameters_Base = 34,
Multisynth0Parameters_Base = 42,
Multisynth1Parameters_Base = 50,
Multisynth2Parameters_Base = 58,
Multisynth3Parameters_Base = 66,
Multisynth4Parameters_Base = 74,
Multisynth5Parameters_Base = 82,
Multisynth6Parameters = 90,
Multisynth7Parameters = 91,
Clock6And7OutputDivider = 92,
SpreadSpectrumParameters_Base = 149,
VCXOParameters_Base = 162,
CLKInitialPhaseOffset_Base = 165,
PLLReset = 177,
CrystalInternalLoadCapacitance = 183,
FanoutEnable = 187,
};
}
namespace DeviceStatus {
using Type = uint8_t;
using Type = uint8_t;
enum {
REVID_Mask = (0b11 << 0),
enum {
REVID_Mask = (0b11 << 0),
LOS_Mask = (1 << 4),
LOS_ValidClockAtCLKIN = (0 << 4),
LOS_LossOfSignalAtCLKIN = (1 << 4),
LOS_Mask = (1 << 4),
LOS_ValidClockAtCLKIN = (0 << 4),
LOS_LossOfSignalAtCLKIN = (1 << 4),
LOL_A_Mask = (1 << 5),
LOL_A_PLLALocked = (0 << 5),
LOL_A_PLLAUnlocked = (1 << 5),
LOL_A_Mask = (1 << 5),
LOL_A_PLLALocked = (0 << 5),
LOL_A_PLLAUnlocked = (1 << 5),
LOL_B_Mask = (1 << 6),
LOL_B_PLLBLocked = (0 << 6),
LOL_B_PLLBUnlocked = (1 << 6),
LOL_B_Mask = (1 << 6),
LOL_B_PLLBLocked = (0 << 6),
LOL_B_PLLBUnlocked = (1 << 6),
SYS_INIT_Mask = (1 << 7),
SYS_INIT_Complete = (0 << 7),
SYS_INIT_Initializing = (1 << 7),
};
}
SYS_INIT_Mask = (1 << 7),
SYS_INIT_Complete = (0 << 7),
SYS_INIT_Initializing = (1 << 7),
};
} // namespace DeviceStatus
struct ClockControl {
enum ClockCurrentDrive {
_2mA = 0b00,
_4mA = 0b01,
_6mA = 0b10,
_8mA = 0b11,
};
enum ClockCurrentDrive {
_2mA = 0b00,
_4mA = 0b01,
_6mA = 0b10,
_8mA = 0b11,
};
enum ClockSource {
Xtal = 0b00,
CLKIN = 0b01,
MS_Group = 0b10,
MS_Self = 0b11,
};
enum ClockSource {
Xtal = 0b00,
CLKIN = 0b01,
MS_Group = 0b10,
MS_Self = 0b11,
};
enum ClockInvert {
Normal = 0,
Invert = 1,
};
enum ClockInvert {
Normal = 0,
Invert = 1,
};
enum MultiSynthSource {
PLLA = 0,
PLLB = 1,
};
enum MultiSynthSource {
PLLA = 0,
PLLB = 1,
};
enum MultiSynthMode {
Fractional = 0,
Integer = 1,
};
enum MultiSynthMode {
Fractional = 0,
Integer = 1,
};
enum ClockPowerDown {
Power_On = 0,
Power_Off = 1,
};
enum ClockPowerDown {
Power_On = 0,
Power_Off = 1,
};
reg_t CLK_IDRV : 2;
reg_t CLK_SRC : 2;
reg_t CLK_INV : 1;
reg_t MS_SRC : 1;
reg_t MS_INT : 1;
reg_t CLK_PDN : 1;
reg_t CLK_IDRV : 2;
reg_t CLK_SRC : 2;
reg_t CLK_INV : 1;
reg_t MS_SRC : 1;
reg_t MS_INT : 1;
reg_t CLK_PDN : 1;
constexpr ClockControl(
ClockCurrentDrive clk_idrv,
ClockSource clk_src,
ClockInvert clk_inv,
MultiSynthSource ms_src,
MultiSynthMode ms_int,
ClockPowerDown clk_pdn
) : CLK_IDRV(clk_idrv),
CLK_SRC(clk_src),
CLK_INV(clk_inv),
MS_SRC(ms_src),
MS_INT(ms_int),
CLK_PDN(clk_pdn)
{
}
constexpr ClockControl(
ClockCurrentDrive clk_idrv,
ClockSource clk_src,
ClockInvert clk_inv,
MultiSynthSource ms_src,
MultiSynthMode ms_int,
ClockPowerDown clk_pdn)
: CLK_IDRV(clk_idrv),
CLK_SRC(clk_src),
CLK_INV(clk_inv),
MS_SRC(ms_src),
MS_INT(ms_int),
CLK_PDN(clk_pdn) {
}
ClockControl clk_src(const ClockSource value) const {
auto result = *this;
result.CLK_SRC = value;
return result;
}
ClockControl ms_src(const MultiSynthSource value) const {
auto result = *this;
result.MS_SRC = value;
return result;
}
ClockControl clk_src(const ClockSource value) const {
auto result = *this;
result.CLK_SRC = value;
return result;
}
ClockControl clk_pdn(const ClockPowerDown value) const {
auto result = *this;
result.CLK_PDN = value;
return result;
}
ClockControl ms_src(const MultiSynthSource value) const {
auto result = *this;
result.MS_SRC = value;
return result;
}
constexpr operator reg_t() {
return *reinterpret_cast<reg_t*>(this);
}
ClockControl clk_pdn(const ClockPowerDown value) const {
auto result = *this;
result.CLK_PDN = value;
return result;
}
static constexpr ClockControl power_off() {
return {
ClockCurrentDrive::_2mA,
ClockSource::Xtal,
ClockInvert::Normal,
MultiSynthSource::PLLA,
MultiSynthMode::Fractional,
ClockPowerDown::Power_Off,
};
}
constexpr operator reg_t() {
return *reinterpret_cast<reg_t*>(this);
}
static constexpr ClockControl power_off() {
return {
ClockCurrentDrive::_2mA,
ClockSource::Xtal,
ClockInvert::Normal,
MultiSynthSource::PLLA,
MultiSynthMode::Fractional,
ClockPowerDown::Power_Off,
};
}
};
static_assert(sizeof(ClockControl) == 1, "ClockControl size is not eight bits");
@@ -195,302 +194,294 @@ static_assert(sizeof(ClockControl) == 1, "ClockControl size is not eight bits");
using ClockControls = std::array<ClockControl, 8>;
namespace CrystalInternalLoadCapacitance {
using Type = uint8_t;
using Type = uint8_t;
enum {
XTAL_CL_Mask = (0b11 << 6),
XTAL_CL_6pF = (0b01 << 6),
XTAL_CL_8pF = (0b10 << 6),
XTAL_CL_10pF = (0b11 << 6),
};
}
enum {
XTAL_CL_Mask = (0b11 << 6),
XTAL_CL_6pF = (0b01 << 6),
XTAL_CL_8pF = (0b10 << 6),
XTAL_CL_10pF = (0b11 << 6),
};
} // namespace CrystalInternalLoadCapacitance
namespace PLLInputSource {
using Type = uint8_t;
using Type = uint8_t;
enum {
PLLA_Source_Mask = (1 << 2),
PLLA_Source_XTAL = (0 << 2),
PLLA_Source_CLKIN = (1 << 2),
enum {
PLLA_Source_Mask = (1 << 2),
PLLA_Source_XTAL = (0 << 2),
PLLA_Source_CLKIN = (1 << 2),
PLLB_Source_Mask = (1 << 3),
PLLB_Source_XTAL = (0 << 3),
PLLB_Source_CLKIN = (1 << 3),
PLLB_Source_Mask = (1 << 3),
PLLB_Source_XTAL = (0 << 3),
PLLB_Source_CLKIN = (1 << 3),
CLKIN_Div_Mask = (0b11 << 6),
CLKIN_Div1 = (0b00 << 6),
CLKIN_Div2 = (0b01 << 6),
CLKIN_Div4 = (0b10 << 6),
CLKIN_Div8 = (0b11 << 6),
};
}
CLKIN_Div_Mask = (0b11 << 6),
CLKIN_Div1 = (0b00 << 6),
CLKIN_Div2 = (0b01 << 6),
CLKIN_Div4 = (0b10 << 6),
CLKIN_Div8 = (0b11 << 6),
};
} // namespace PLLInputSource
struct Inputs {
const uint32_t f_xtal;
const uint32_t f_clkin;
const uint32_t clkin_div;
const uint32_t f_xtal;
const uint32_t f_clkin;
const uint32_t clkin_div;
constexpr uint32_t f_clkin_out() const {
return f_clkin / clkin_div;
}
constexpr uint32_t f_clkin_out() const {
return f_clkin / clkin_div;
}
};
using PLLReg = std::array<uint8_t, 9>;
struct PLL {
const uint32_t f_in;
const uint32_t a;
const uint32_t b;
const uint32_t c;
const uint32_t f_in;
const uint32_t a;
const uint32_t b;
const uint32_t c;
constexpr uint32_t f_vco() const {
return f_in * (a + (float)b / (float)c);
}
constexpr uint32_t f_vco() const {
return f_in * (a + (float)b / (float)c);
}
constexpr uint32_t p1() const {
return 128 * a + (uint32_t)(128 * (float)b / (float)c) - 512;
}
constexpr uint32_t p1() const {
return 128 * a + (uint32_t)(128 * (float)b / (float)c) - 512;
}
constexpr uint32_t p2() const {
return 128 * b - c * (uint32_t)(128 * (float)b / (float)c);
}
constexpr uint32_t p2() const {
return 128 * b - c * (uint32_t)(128 * (float)b / (float)c);
}
constexpr uint32_t p3() const {
return c;
}
constexpr uint32_t p3() const {
return c;
}
constexpr PLLReg reg(const uint8_t pll_n) const {
return {
uint8_t(26 + (pll_n * 8)),
uint8_t((p3() >> 8) & 0xff),
uint8_t((p3() >> 0) & 0xff),
uint8_t((p1() >> 16) & 0x03),
uint8_t((p1() >> 8) & 0xff),
uint8_t((p1() >> 0) & 0xff),
uint8_t(
(((p3() >> 16) & 0x0f) << 4)
| ((p2() >> 16) & 0x0f)
),
uint8_t((p2() >> 8) & 0xff),
uint8_t((p2() >> 0) & 0xff),
};
}
constexpr PLLReg reg(const uint8_t pll_n) const {
return {
uint8_t(26 + (pll_n * 8)),
uint8_t((p3() >> 8) & 0xff),
uint8_t((p3() >> 0) & 0xff),
uint8_t((p1() >> 16) & 0x03),
uint8_t((p1() >> 8) & 0xff),
uint8_t((p1() >> 0) & 0xff),
uint8_t(
(((p3() >> 16) & 0x0f) << 4) | ((p2() >> 16) & 0x0f)),
uint8_t((p2() >> 8) & 0xff),
uint8_t((p2() >> 0) & 0xff),
};
}
};
using MultisynthFractionalReg = std::array<uint8_t, 9>;
struct MultisynthFractional {
const uint32_t f_src;
const uint32_t a;
const uint32_t b;
const uint32_t c;
const uint32_t r_div;
const uint32_t f_src;
const uint32_t a;
const uint32_t b;
const uint32_t c;
const uint32_t r_div;
constexpr uint32_t p1() const {
return 128 * a + (uint32_t)(128 * (float)b / (float)c) - 512;
}
constexpr uint32_t p1() const {
return 128 * a + (uint32_t)(128 * (float)b / (float)c) - 512;
}
constexpr uint32_t p2() const {
return 128 * b - c * (uint32_t)(128 * (float)b / (float)c);
}
constexpr uint32_t p2() const {
return 128 * b - c * (uint32_t)(128 * (float)b / (float)c);
}
constexpr uint32_t p3() const {
return c;
}
constexpr uint32_t p3() const {
return c;
}
constexpr uint32_t f_out() const {
return f_src / (a + (float)b / (float)c) / (1 << r_div);
}
constexpr uint32_t f_out() const {
return f_src / (a + (float)b / (float)c) / (1 << r_div);
}
constexpr MultisynthFractionalReg reg(const uint8_t multisynth_n) const {
return {
uint8_t(42 + (multisynth_n * 8)),
uint8_t((p3() >> 8) & 0xFF),
uint8_t((p3() >> 0) & 0xFF),
uint8_t((r_div << 4) | (0 << 2) | ((p1() >> 16) & 0x3)),
uint8_t((p1() >> 8) & 0xFF),
uint8_t((p1() >> 0) & 0xFF),
uint8_t((((p3() >> 16) & 0xF) << 4) | (((p2() >> 16) & 0xF) << 0)),
uint8_t((p2() >> 8) & 0xFF),
uint8_t((p2() >> 0) & 0xFF)
};
}
constexpr MultisynthFractionalReg reg(const uint8_t multisynth_n) const {
return {
uint8_t(42 + (multisynth_n * 8)),
uint8_t((p3() >> 8) & 0xFF),
uint8_t((p3() >> 0) & 0xFF),
uint8_t((r_div << 4) | (0 << 2) | ((p1() >> 16) & 0x3)),
uint8_t((p1() >> 8) & 0xFF),
uint8_t((p1() >> 0) & 0xFF),
uint8_t((((p3() >> 16) & 0xF) << 4) | (((p2() >> 16) & 0xF) << 0)),
uint8_t((p2() >> 8) & 0xFF),
uint8_t((p2() >> 0) & 0xFF)};
}
};
struct MultisynthInteger {
const uint32_t f_src;
const uint32_t a;
const uint32_t r_div;
const uint32_t f_src;
const uint32_t a;
const uint32_t r_div;
constexpr uint8_t p1() const {
return a;
}
constexpr uint8_t p1() const {
return a;
}
constexpr uint32_t f_out() const {
return f_src / a / (1 << r_div);
}
constexpr uint32_t f_out() const {
return f_src / a / (1 << r_div);
}
};
using Multisynth6And7Reg = std::array<uint8_t, 4>;
constexpr Multisynth6And7Reg ms6_7_reg(
const MultisynthInteger& ms6,
const MultisynthInteger& ms7
) {
return {
Register::Multisynth6Parameters,
uint8_t(ms6.p1() & 0xff),
uint8_t(ms7.p1() & 0xff),
uint8_t(((ms7.r_div & 7) << 4) | ((ms6.r_div & 7) << 0)),
};
const MultisynthInteger& ms6,
const MultisynthInteger& ms7) {
return {
Register::Multisynth6Parameters,
uint8_t(ms6.p1() & 0xff),
uint8_t(ms7.p1() & 0xff),
uint8_t(((ms7.r_div & 7) << 4) | ((ms6.r_div & 7) << 0)),
};
}
class Si5351 {
public:
using regvalue_t = uint8_t;
public:
using regvalue_t = uint8_t;
constexpr Si5351(I2C& bus, I2C::address_t address) :
_clock_control({
ClockControl::power_off(), ClockControl::power_off(),
ClockControl::power_off(), ClockControl::power_off(),
ClockControl::power_off(), ClockControl::power_off(),
ClockControl::power_off(), ClockControl::power_off()
}),
_bus(bus),
_address(address),
_output_enable(0x00)
{
}
constexpr Si5351(I2C& bus, I2C::address_t address)
: _clock_control({ClockControl::power_off(), ClockControl::power_off(),
ClockControl::power_off(), ClockControl::power_off(),
ClockControl::power_off(), ClockControl::power_off(),
ClockControl::power_off(), ClockControl::power_off()}),
_bus(bus),
_address(address),
_output_enable(0x00) {
}
void reset();
void reset();
uint8_t device_status() {
return read_register(Register::DeviceStatus);
}
uint8_t device_status() {
return read_register(Register::DeviceStatus);
}
void wait_for_device_ready() {
while(device_status() & 0x80);
}
void wait_for_device_ready() {
while (device_status() & 0x80)
;
}
bool plla_loss_of_signal() {
return (device_status() >> 5) & 1;
}
bool plla_loss_of_signal() {
return (device_status() >> 5) & 1;
}
bool clkin_loss_of_signal() {
return (device_status() >> 4) & 1;
}
void enable_fanout() {
write_register(Register::FanoutEnable, 0b11010000);
}
bool clkin_loss_of_signal() {
return (device_status() >> 4) & 1;
}
void reset_plls() {
// Datasheet recommends value 0xac, though the low nibble bits are not defined in AN619.
write_register(Register::PLLReset, 0xac);
}
void enable_fanout() {
write_register(Register::FanoutEnable, 0b11010000);
}
regvalue_t read_register(const uint8_t reg);
void reset_plls() {
// Datasheet recommends value 0xac, though the low nibble bits are not defined in AN619.
write_register(Register::PLLReset, 0xac);
}
template<size_t N>
void write(const std::array<uint8_t, N>& values) {
_bus.transmit(_address, values.data(), values.size());
}
regvalue_t read_register(const uint8_t reg);
void write_register(const uint8_t reg, const regvalue_t value) {
write(std::array<uint8_t, 2>{
reg, value
});
}
template <size_t N>
void write(const std::array<uint8_t, N>& values) {
_bus.transmit(_address, values.data(), values.size());
}
void write(const size_t ms_number, const MultisynthFractional& config) {
write(config.reg(ms_number));
}
void write_register(const uint8_t reg, const regvalue_t value) {
write(std::array<uint8_t, 2>{
reg, value});
}
void set_ms_frequency(
const size_t ms_number,
const uint32_t frequency,
const uint32_t vco_frequency,
const size_t r_div
);
void write(const size_t ms_number, const MultisynthFractional& config) {
write(config.reg(ms_number));
}
void set_crystal_internal_load_capacitance(const CrystalInternalLoadCapacitance::Type xtal_cl) {
write_register(Register::CrystalInternalLoadCapacitance, xtal_cl);
}
void set_ms_frequency(
const size_t ms_number,
const uint32_t frequency,
const uint32_t vco_frequency,
const size_t r_div);
void set_pll_input_sources(const PLLInputSource::Type value) {
write_register(Register::PLLInputSource, value);
}
void set_crystal_internal_load_capacitance(const CrystalInternalLoadCapacitance::Type xtal_cl) {
write_register(Register::CrystalInternalLoadCapacitance, xtal_cl);
}
void enable_output_mask(const uint8_t mask) {
_output_enable |= mask;
update_output_enable_control();
}
void set_pll_input_sources(const PLLInputSource::Type value) {
write_register(Register::PLLInputSource, value);
}
void enable_output(const size_t n) {
enable_output_mask(1 << n);
}
void enable_output_mask(const uint8_t mask) {
_output_enable |= mask;
update_output_enable_control();
}
void disable_output_mask(const uint8_t mask) {
_output_enable &= ~mask;
update_output_enable_control();
}
void enable_output(const size_t n) {
enable_output_mask(1 << n);
}
void disable_output(const size_t n) {
disable_output_mask(1 << n);
}
void disable_output_mask(const uint8_t mask) {
_output_enable &= ~mask;
update_output_enable_control();
}
void set_clock_control(const ClockControls& clock_control) {
_clock_control = clock_control;
update_all_clock_control();
}
void disable_output(const size_t n) {
disable_output_mask(1 << n);
}
void set_clock_control(const size_t n, const ClockControl clock_control) {
_clock_control[n] = clock_control;
write_register(Register::CLKControl_Base + n, _clock_control[n]);
}
void set_clock_control(const ClockControls& clock_control) {
_clock_control = clock_control;
update_all_clock_control();
}
void enable_clock(const size_t n) {
_clock_control[n].CLK_PDN = ClockControl::ClockPowerDown::Power_On;
write_register(Register::CLKControl_Base + n, _clock_control[n]);
}
void set_clock_control(const size_t n, const ClockControl clock_control) {
_clock_control[n] = clock_control;
write_register(Register::CLKControl_Base + n, _clock_control[n]);
}
void disable_clock(const size_t n) {
_clock_control[n].CLK_PDN = ClockControl::ClockPowerDown::Power_Off;
write_register(Register::CLKControl_Base + n, _clock_control[n]);
}
void enable_clock(const size_t n) {
_clock_control[n].CLK_PDN = ClockControl::ClockPowerDown::Power_On;
write_register(Register::CLKControl_Base + n, _clock_control[n]);
}
template<size_t N>
void write_registers(const uint8_t reg, const std::array<uint8_t, N>& values) {
std::array<uint8_t, N + 1> data;
data[0] = reg;
std::copy(values.cbegin(), values.cend(), data.begin() + 1);
write(data);
}
void disable_clock(const size_t n) {
_clock_control[n].CLK_PDN = ClockControl::ClockPowerDown::Power_Off;
write_register(Register::CLKControl_Base + n, _clock_control[n]);
}
private:
ClockControls _clock_control;
I2C& _bus;
const I2C::address_t _address;
uint8_t _output_enable;
template <size_t N>
void write_registers(const uint8_t reg, const std::array<uint8_t, N>& values) {
std::array<uint8_t, N + 1> data;
data[0] = reg;
std::copy(values.cbegin(), values.cend(), data.begin() + 1);
write(data);
}
void update_output_enable_control() {
write_register(Register::OutputEnableControl, ~_output_enable);
}
private:
ClockControls _clock_control;
I2C& _bus;
const I2C::address_t _address;
uint8_t _output_enable;
void update_all_clock_control() {
write_registers(Register::CLKControl_Base, std::array<reg_t, 8> { {
_clock_control[0],
_clock_control[1],
_clock_control[2],
_clock_control[3],
_clock_control[4],
_clock_control[5],
_clock_control[6],
_clock_control[7],
} });
}
void update_output_enable_control() {
write_register(Register::OutputEnableControl, ~_output_enable);
}
void update_all_clock_control() {
write_registers(Register::CLKControl_Base, std::array<reg_t, 8>{{
_clock_control[0],
_clock_control[1],
_clock_control[2],
_clock_control[3],
_clock_control[4],
_clock_control[5],
_clock_control[6],
_clock_control[7],
}});
}
};
}
} // namespace si5351
#endif/*__SI5351_H__*/
#endif /*__SI5351_H__*/

View File

@@ -30,48 +30,46 @@ namespace spi {
namespace arbiter {
class Arbiter {
public:
constexpr Arbiter(
SPI& bus
) : _bus(bus),
_config(nullptr)
{
}
public:
constexpr Arbiter(
SPI& bus)
: _bus(bus),
_config(nullptr) {
}
void transfer(const SPIConfig* const config, void* const data, const size_t count) {
if( config != _config ) {
_bus.stop();
_bus.start(*config);
_config = config;
}
_bus.transfer(data, count);
}
void transfer(const SPIConfig* const config, void* const data, const size_t count) {
if (config != _config) {
_bus.stop();
_bus.start(*config);
_config = config;
}
_bus.transfer(data, count);
}
private:
SPI& _bus;
const SPIConfig* _config;
private:
SPI& _bus;
const SPIConfig* _config;
};
class Target {
public:
constexpr Target(
Arbiter& arbiter,
const SPIConfig& config
) : _arbiter(arbiter),
_config(config)
{
}
public:
constexpr Target(
Arbiter& arbiter,
const SPIConfig& config)
: _arbiter(arbiter),
_config(config) {
}
void transfer(void* const data, const size_t count) {
_arbiter.transfer(&_config, data, count);
}
void transfer(void* const data, const size_t count) {
_arbiter.transfer(&_config, data, count);
}
private:
Arbiter& _arbiter;
const SPIConfig _config;
private:
Arbiter& _arbiter;
const SPIConfig _config;
};
} /* arbiter */
} /* spi */
} // namespace arbiter
} // namespace spi
#endif/*__SPI_ARBITER_H__*/
#endif /*__SPI_ARBITER_H__*/

View File

@@ -28,29 +28,29 @@
#include "hal.h"
class SPI {
public:
constexpr SPI(SPIDriver* const driver) :
_driver(driver) {
}
public:
constexpr SPI(SPIDriver* const driver)
: _driver(driver) {
}
void start(const SPIConfig& config) {
spiStart(_driver, &config);
}
void start(const SPIConfig& config) {
spiStart(_driver, &config);
}
void stop() {
spiStop(_driver);
}
void stop() {
spiStop(_driver);
}
void transfer(void* const data, const size_t count) {
spiAcquireBus(_driver);
spiSelect(_driver);
spiExchange(_driver, count, data, data);
spiUnselect(_driver);
spiReleaseBus(_driver);
}
void transfer(void* const data, const size_t count) {
spiAcquireBus(_driver);
spiSelect(_driver);
spiExchange(_driver, count, data, data);
spiUnselect(_driver);
spiReleaseBus(_driver);
}
private:
SPIDriver* const _driver;
private:
SPIDriver* const _driver;
};
#endif/*__SPI_PP_H__*/
#endif /*__SPI_PP_H__*/

View File

@@ -39,47 +39,43 @@ namespace touch {
namespace adc {
constexpr uint8_t adc0_sel =
(1 << portapack::adc0_touch_xp_input)
| (1 << portapack::adc0_touch_xn_input)
| (1 << portapack::adc0_touch_yp_input)
| (1 << portapack::adc0_touch_yn_input)
;
(1 << portapack::adc0_touch_xp_input) | (1 << portapack::adc0_touch_xn_input) | (1 << portapack::adc0_touch_yp_input) | (1 << portapack::adc0_touch_yn_input);
const auto adc0_interrupt_mask = flp2(adc0_sel);
constexpr lpc43xx::adc::CR adc0_cr {
.sel = adc0_sel,
.clkdiv = 49, /* 400kHz sample rate, 2.5us/sample @ 200MHz PCLK */
.resolution = 9, /* Ten clocks */
.edge = 0,
constexpr lpc43xx::adc::CR adc0_cr{
.sel = adc0_sel,
.clkdiv = 49, /* 400kHz sample rate, 2.5us/sample @ 200MHz PCLK */
.resolution = 9, /* Ten clocks */
.edge = 0,
};
constexpr lpc43xx::adc::Config adc0_config {
.cr = adc0_cr,
constexpr lpc43xx::adc::Config adc0_config{
.cr = adc0_cr,
};
void init() {
adc0::clock_enable();
adc0::interrupts_disable();
adc0::power_up(adc0_config);
adc0::interrupts_enable(adc0_interrupt_mask);
adc0::clock_enable();
adc0::interrupts_disable();
adc0::power_up(adc0_config);
adc0::interrupts_enable(adc0_interrupt_mask);
}
void start() {
adc0::start_burst();
adc0::start_burst();
}
// static constexpr bool monitor_overruns_and_not_dones = false;
Samples get() {
const auto xp_reg = LPC_ADC0->DR[portapack::adc0_touch_xp_input];
const auto xn_reg = LPC_ADC0->DR[portapack::adc0_touch_xn_input];
const auto yp_reg = LPC_ADC0->DR[portapack::adc0_touch_yp_input];
const auto yn_reg = LPC_ADC0->DR[portapack::adc0_touch_yn_input];
return {
(xp_reg >> 6) & 0x3ff,
(xn_reg >> 6) & 0x3ff,
(yp_reg >> 6) & 0x3ff,
(yn_reg >> 6) & 0x3ff,
};
const auto xp_reg = LPC_ADC0->DR[portapack::adc0_touch_xp_input];
const auto xn_reg = LPC_ADC0->DR[portapack::adc0_touch_xn_input];
const auto yp_reg = LPC_ADC0->DR[portapack::adc0_touch_yp_input];
const auto yn_reg = LPC_ADC0->DR[portapack::adc0_touch_yn_input];
return {
(xp_reg >> 6) & 0x3ff,
(xn_reg >> 6) & 0x3ff,
(yp_reg >> 6) & 0x3ff,
(yn_reg >> 6) & 0x3ff,
};
}
} /* namespace adc */

View File

@@ -35,4 +35,4 @@ Samples get();
} /* namespace adc */
} /* namespace touch */
#endif/*__TOUCH_ADC_H__*/
#endif /*__TOUCH_ADC_H__*/