portapack-mayhem/firmware/application/hw/si5351.cpp

100 lines
3.1 KiB
C++
Raw Normal View History

2015-07-08 15:39:24 +00:00
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "si5351.hpp"
#include "utility.hpp"
#include <cstdint>
#include <array>
namespace si5351 {
void Si5351::reset() {
wait_for_device_ready();
2015-07-08 15:39:24 +00:00
write_register(Register::InterruptStatusSticky, 0x00);
write_register(Register::InterruptStatusMask, 0xf0);
2015-07-08 15:39:24 +00:00
disable_output_mask(0xff);
write_register(Register::OEBPinEnableControlMask, 0xff);
write_register(Register::PLLInputSource, 0x00);
2015-07-08 15:39:24 +00:00
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()});
2015-07-08 15:39:24 +00:00
write(std::array<uint8_t, 70>{Register::CLK3_0DisableState});
2015-07-08 15:39:24 +00:00
write(std::array<uint8_t, 14>{
Register::SpreadSpectrumParameters_Base});
2015-07-08 15:39:24 +00:00
write(std::array<uint8_t, 4>{
Register::VCXOParameters_Base});
2015-07-08 15:39:24 +00:00
write(std::array<uint8_t, 7>{
Register::CLKInitialPhaseOffset_Base});
2015-07-08 15:39:24 +00:00
write_register(Register::CrystalInternalLoadCapacitance, 0b11010010);
write_register(Register::FanoutEnable, 0x00);
2015-07-08 15:39:24 +00:00
reset_plls();
2015-07-08 15:39:24 +00:00
}
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];
2015-07-08 15:39:24 +00:00
}
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;
/* 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);
2015-07-08 15:39:24 +00:00
}
} /* namespace si5351 */