peary/hardware/boards/Carboard.hpp

Carboard Class. More…

Namespaces

Name
peary
peary::board
peary::board::carboard

Classes

Name
class peary::board::carboard::EEPROM EEPROM resource for CaR board.
class peary::board::carboard::ClockGenerator Clock generator resource for CaR board.
class peary::board::carboard::ZynqClockGenerator Clock generator resource on Zynq board.
class peary::board::carboard::TemperatureSensor Temperature sensor resource for CaR board.
class peary::board::carboard::ADCInput ADC input resource for CaR board.
class peary::board::carboard::BiasRegulator Bias voltage regulator resource for CaR board.
class peary::board::carboard::CMOSLevels CMOS level shifter resource for CaR board.
class peary::board::carboard::CurrentSource Current source resource for CaR board.
class peary::board::carboard::VoltageRegulator Voltage regulator resource for CaR board.
class peary::board::carboard::Carboard Carboard class representing the CaR board.

Detailed Description

Carboard Class.

Copyright: Copyright (c) 2016-2025 CERN and the Peary Caribou authors. This software is distributed under the terms of the LGPL-3.0-only License, copied verbatim in the file “LICENSE.md”. SPDX-License-Identifier: LGPL-3.0-only

Source code

  
#pragma once

#include <any>
#include <chrono>
#include <thread>

#include "peary/hal/Board.hpp"
#include "peary/hal/Resources.hpp"
#include "peary/hardware/boards/CarboardConstants.hpp"
#include "peary/hardware/components/ADS7828.hpp"
#include "peary/hardware/components/DAC7678.hpp"
#include "peary/hardware/components/EEPROM24LC32A.hpp"
#include "peary/hardware/components/INA226.hpp"
#include "peary/hardware/components/PCA9539.hpp"
#include "peary/hardware/components/Si5345.hpp"
#include "peary/hardware/components/Si570.hpp"
#include "peary/hardware/components/TMP101.hpp"

namespace peary::board::carboard {

    class EEPROM : public hal::E2Writer, public hal::E2Reader {
    public:
        EEPROM(component::EEPROM24LC32A& eeprom) noexcept : _eeprom(eeprom) {}

        void write(uint16_t address, int value) override { _eeprom.write(address, static_cast<uint8_t>(value)); }

        uint8_t read(uint16_t address) override { return _eeprom.read(address); }

        int getBoardID() {
            LOG(DEBUG) << "Reading board ID from CaR EEPROM";
            return _eeprom.read(ADDR_EEPROM_BOARD_ID);
        }

    private:
        // Reference to the EEPROM24LC32A component
        component::EEPROM24LC32A& _eeprom;
    };

    class ClockGenerator : public hal::ClockSynthesizer {
    public:
        ClockGenerator(component::Si5345& si5345) noexcept : _si5345(si5345) {}

        void configure(const std::any& config) override { _si5345.configure(config); }

        void disable() override { _si5345.disable(); }

        bool isLocked() override { return _si5345.isLocked(); }

        interface::iface_i2c::dataVector_type read(int page) { return _si5345.read(page); }

    private:
        // Reference to the Si5345 component
        component::Si5345& _si5345;
    };

    class ZynqClockGenerator : public hal::Oscillator {
    public:
        ZynqClockGenerator(component::Si570& si570) noexcept : _si570(si570) {}

        void setFrequency(uint64_t frequency) override { _si570.setFrequency(frequency); }

    private:
        // Reference to the Si570 component
        component::Si570& _si570;
    };

    class TemperatureSensor : public hal::TemperatureProvider {
    public:
        TemperatureSensor(component::TMP101& sensor) noexcept : _sensor(sensor) {}

        double getTemperature() override { return _sensor.readTemperature(); }

    private:
        // Reference to the TMP101 component
        component::TMP101& _sensor;
    };

    class ADCInput : public hal::VoltageProvider {
    public:
        ADCInput(component::ADS7828& adc, component::ADS7828::Channel channel) noexcept : _adc(adc), _channel(channel) {}

        double getVoltage() override { return (_adc.readSingleEnded(_channel)); }

    private:
        // Reference to the ADS7828 component
        component::ADS7828& _adc;
        // ADS7828 channel to read from
        component::ADS7828::Channel _channel;
    };

    class BiasRegulator : public hal::VoltageControl, public hal::SwitchControl {
    public:
        BiasRegulator(component::DAC7678& dac, component::DAC7678::Channel channel) noexcept
            : _dac(dac), _channel(channel) {}

        void setVoltage(double voltage) override { _dac.setVoltage(_channel, voltage); }

        void setSwitch(bool enable) override { _dac.setOutput(_channel, enable); }

    private:
        // Reference to the DAC7678 component
        component::DAC7678& _dac;
        // DAC7678 channel to control
        component::DAC7678::Channel _channel;
    };

    class CMOSLevels : public hal::VoltageControl, public hal::SwitchControl {
    public:
        CMOSLevels(component::DAC7678& dac, std::vector<component::DAC7678::Channel> channels) noexcept
            : _dac(dac), _channels(std::move(channels)) {}

        void setVoltage(double voltage) override {
            for(auto channel : _channels) {
                _dac.setVoltage(channel, voltage);
            }
        }

        void setSwitch(bool enable) override {
            for(auto channel : _channels) {
                _dac.setOutput(channel, enable);
            }
        }

    private:
        // Reference to the DAC7678 component
        component::DAC7678& _dac;
        // DAC7678 channels to control
        std::vector<component::DAC7678::Channel> _channels;
    };

    class CurrentSource : public hal::CurrentControl, public hal::SwitchControl {
    public:
        CurrentSource(component::DAC7678& dac,
                      component::DAC7678::Channel dac_channel,
                      component::PCA9539& pca,
                      component::PCA9539::Port pca_port,
                      component::PCA9539::Channel pca_channel) noexcept
            : _dac(dac), _dac_channel(dac_channel), _pca(pca), _pca_port(pca_port), _pca_channel(pca_channel) {

            // Set the PCA9539 channel as output
            _pca.setDirection(_pca_port, _pca_channel, utils::Direction::OUT);
        };

        void setCurrent(double current) override {
            // FIXME this is in uA right now, should go to A
            LOG(DEBUG) << "Setting " << current << "A " << "on " << name();

            if(current > 1.024e-3) {
                throw utils::InvalidArgumentError(
                    __func__, "Trying to set current source to " + std::to_string(current) + " A (max is 1.024e-3 A)");
            }

            // The output current is set by Vdac connected to a 1/40 voltage divider and sensed by a 100 Ohm resistor
            // So the output current is Vdac / 40 / 100 Ohm
            _dac.setVoltage(_dac_channel, current * 40 * 1000);
        }

        void setSwitch(bool enable) override { _dac.setOutput(_dac_channel, enable); }

        void setPolarity(utils::Polarity polarity) override { _pca.setOutputLevel(_pca_port, _pca_channel, polarity); }

    private:
        // Reference to the DAC7678 component
        component::DAC7678& _dac;
        // DAC7678 channel to control the current source
        component::DAC7678::Channel _dac_channel;
        // Reference to the PCA9539 component
        component::PCA9539& _pca;
        // PCA9539 port to control the polarity
        component::PCA9539::Port _pca_port;
        // PCA9539 channel to control the polarity
        component::PCA9539::Channel _pca_channel;
    };

    class VoltageRegulator : public hal::VoltageControl,
                             public hal::VoltageProvider,
                             public hal::CurrentLimiter,
                             public hal::CurrentProvider,
                             public hal::PowerProvider,
                             public hal::SwitchControl,
                             public hal::AlertMonitor {
    public:
        VoltageRegulator(component::DAC7678& dac,
                         component::DAC7678::Channel dac_channel,
                         component::INA226& ina,
                         component::PCA9539& pca_pwr,
                         component::PCA9539::Port pca_pwr_port,
                         component::PCA9539::Channel pca_pwr_channel,
                         component::PCA9539& pca_alert,
                         component::PCA9539::Port pca_alert_port,
                         component::PCA9539::Channel pca_alert_channel) noexcept
            : _dac(dac), _dac_channel(dac_channel), _ina(ina), _pca_pwr(pca_pwr), _pca_pwr_port(pca_pwr_port),
              _pca_pwr_channel(pca_pwr_channel), _pca_alert(pca_alert), _pca_alert_port(pca_alert_port),
              _pca_alert_channel(pca_alert_channel) {

            // Set the PCA9539 channel as output
            _pca_pwr.setDirection(_pca_pwr_port, _pca_pwr_channel, utils::Direction::OUT);
        };

        void setVoltage(double voltage) override {
            // Check if the voltage is within the valid range
            if(voltage > 3.5 || voltage < 0) {
                throw utils::InvalidArgumentError(
                    __func__, "Trying to set Voltage regulator to " + std::to_string(voltage) + " V (range is 0-3.5 V)");
            }
            // Set voltage on the DAC7678
            LOG(DEBUG) << "Setting voltage " << voltage << "V " << "on " << name();
            _dac.setVoltage(_dac_channel, 3.6 - voltage);
        }

        void setCurrentLimit(double current_limit) override {
            // Set the current limit on the INA226
            _ina.setCurrentLimit(current_limit);
        }

        void setSwitch(bool enable) override {
            using namespace std::chrono_literals;
            if(enable) {
                _dac.setOutput(_dac_channel, enable);
                std::this_thread::sleep_for(100ms);
                _pca_pwr.setOutputLevel(_pca_pwr_port, _pca_pwr_channel, utils::Polarity::HIGH);
            } else {
                _pca_pwr.setOutputLevel(_pca_pwr_port, _pca_pwr_channel, utils::Polarity::LOW);
                _dac.setOutput(_dac_channel, enable);
            }
        }

        double getVoltage() override { return _ina.getVoltage(); }

        double getCurrent() override { return _ina.getCurrent(); }

        double getPower() override { return _ina.getPower(); }

        bool getAlertStatus() override {
            LOG(DEBUG) << "Reading alert status of " << name();
            return _pca_alert.getInputLevel(_pca_alert_port, _pca_alert_channel);
        }

    private:
        // Reference to the DAC7678 component
        component::DAC7678& _dac;
        // DAC7678 channel to control the voltage regulator
        component::DAC7678::Channel _dac_channel;
        // Reference to the INA226 component for voltage, current, and power monitoring
        component::INA226& _ina;
        // Reference to the PCA9539 component for power control
        component::PCA9539& _pca_pwr;
        // PCA9539 port for power control
        component::PCA9539::Port _pca_pwr_port;
        // PCA9539 channel for power control
        component::PCA9539::Channel _pca_pwr_channel;
        // Reference to the PCA9539 component for alert monitoring
        component::PCA9539& _pca_alert;
        // PCA9539 port for alert monitoring
        component::PCA9539::Port _pca_alert_port;
        // PCA9539 channel for alert monitoring
        component::PCA9539::Channel _pca_alert_channel;
    };

    class Carboard : public hal::Board {

    public:
        Carboard()
            : USRCLK(BUS_I2C4, ADDR_SI570),                          //
              SI(BUS_I2C0, ADDR_CLKGEN),                             //
              U30(BUS_I2C0, ADDR_TEMP),                              //
              U15(BUS_I2C0, ADDR_IOEXP), U31(BUS_I2C0, ADDR_IOEXP2), //
              U44(BUS_I2C3, ADDR_DAC_U44, VREF_4P0), U45(BUS_I2C3, ADDR_DAC_U45, VREF_4P0),
              U46(BUS_I2C3, ADDR_DAC_U46, VREF_4P0), U47(BUS_I2C3, ADDR_DAC_U47, VREF_4P0),
              U48(BUS_I2C3, ADDR_DAC_U48, VREF_4P0), U49(BUS_I2C3, ADDR_DAC_U49, VREF_4P0),
              U50(BUS_I2C3, ADDR_DAC_U50, VREF_4P0), U87(BUS_I2C0, ADDR_CMOSDAC, VREF_4P0), //
              U52(BUS_I2C1, ADDR_MONITOR_U52, INA226_R_SHUNT), U53(BUS_I2C1, ADDR_MONITOR_U53, INA226_R_SHUNT),
              U54(BUS_I2C1, ADDR_MONITOR_U54, INA226_R_SHUNT), U55(BUS_I2C1, ADDR_MONITOR_U55, INA226_R_SHUNT),
              U56(BUS_I2C1, ADDR_MONITOR_U56, INA226_R_SHUNT), U57(BUS_I2C1, ADDR_MONITOR_U57, INA226_R_SHUNT),
              U58(BUS_I2C1, ADDR_MONITOR_U58, INA226_R_SHUNT), U59(BUS_I2C1, ADDR_MONITOR_U59, INA226_R_SHUNT), //
              U77(BUS_I2C3, ADDR_ADC, VREF_4P0),                                                                //
              U78(BUS_I2C0, ADDR_EEPROM) {
            // Create resources from board components

            // FIXME: putting this Zynq USR clock here for now
            register_resource<ZynqClockGenerator>("USRCLK", USRCLK);

            // EEPROM access
            register_resource<EEPROM>("EEPROM", U78);

            // Clock Generator
            register_resource<ClockGenerator>("CLKGEN", SI);

            // Temperature sensor
            register_resource<TemperatureSensor>("TEMP", U30);

            // Voltage regulators
            register_resource<VoltageRegulator>("PWR_OUT_1",
                                                U50,
                                                component::DAC7678::VOUTA,
                                                U53,
                                                U15,
                                                component::PCA9539::P1,
                                                component::PCA9539::CH7,
                                                U31,
                                                component::PCA9539::P0,
                                                component::PCA9539::CH7);
            register_resource<VoltageRegulator>("PWR_OUT_2",
                                                U50,
                                                component::DAC7678::VOUTC,
                                                U52,
                                                U15,
                                                component::PCA9539::P1,
                                                component::PCA9539::CH6,
                                                U31,
                                                component::PCA9539::P1,
                                                component::PCA9539::CH0);
            register_resource<VoltageRegulator>("PWR_OUT_3",
                                                U50,
                                                component::DAC7678::VOUTE,
                                                U55,
                                                U15,
                                                component::PCA9539::P1,
                                                component::PCA9539::CH5,
                                                U31,
                                                component::PCA9539::P0,
                                                component::PCA9539::CH6);
            register_resource<VoltageRegulator>("PWR_OUT_4",
                                                U50,
                                                component::DAC7678::VOUTG,
                                                U54,
                                                U15,
                                                component::PCA9539::P1,
                                                component::PCA9539::CH4,
                                                U31,
                                                component::PCA9539::P1,
                                                component::PCA9539::CH1);
            register_resource<VoltageRegulator>("PWR_OUT_5",
                                                U50,
                                                component::DAC7678::VOUTB,
                                                U57,
                                                U15,
                                                component::PCA9539::P1,
                                                component::PCA9539::CH0,
                                                U31,
                                                component::PCA9539::P0,
                                                component::PCA9539::CH0);
            register_resource<VoltageRegulator>("PWR_OUT_6",
                                                U50,
                                                component::DAC7678::VOUTD,
                                                U56,
                                                U15,
                                                component::PCA9539::P1,
                                                component::PCA9539::CH1,
                                                U31,
                                                component::PCA9539::P1,
                                                component::PCA9539::CH6);
            register_resource<VoltageRegulator>("PWR_OUT_7",
                                                U50,
                                                component::DAC7678::VOUTF,
                                                U59,
                                                U15,
                                                component::PCA9539::P1,
                                                component::PCA9539::CH2,
                                                U31,
                                                component::PCA9539::P0,
                                                component::PCA9539::CH1);
            register_resource<VoltageRegulator>("PWR_OUT_8",
                                                U50,
                                                component::DAC7678::VOUTH,
                                                U58,
                                                U15,
                                                component::PCA9539::P1,
                                                component::PCA9539::CH3,
                                                U31,
                                                component::PCA9539::P1,
                                                component::PCA9539::CH7);

            // Current sources
            register_resource<CurrentSource>(
                "CUR_1", U47, component::DAC7678::VOUTB, U15, component::PCA9539::P0, component::PCA9539::CH6);
            register_resource<CurrentSource>(
                "CUR_2", U47, component::DAC7678::VOUTD, U15, component::PCA9539::P0, component::PCA9539::CH7);
            register_resource<CurrentSource>(
                "CUR_3", U47, component::DAC7678::VOUTF, U15, component::PCA9539::P0, component::PCA9539::CH5);
            register_resource<CurrentSource>(
                "CUR_4", U47, component::DAC7678::VOUTH, U15, component::PCA9539::P0, component::PCA9539::CH4);
            register_resource<CurrentSource>(
                "CUR_5", U47, component::DAC7678::VOUTG, U15, component::PCA9539::P0, component::PCA9539::CH2);
            register_resource<CurrentSource>(
                "CUR_6", U47, component::DAC7678::VOUTE, U15, component::PCA9539::P0, component::PCA9539::CH3);
            register_resource<CurrentSource>(
                "CUR_7", U47, component::DAC7678::VOUTC, U15, component::PCA9539::P0, component::PCA9539::CH1);
            register_resource<CurrentSource>(
                "CUR_8", U47, component::DAC7678::VOUTA, U15, component::PCA9539::P0, component::PCA9539::CH0);

            // Bias supplies
            register_resource<BiasRegulator>("BIAS_1", U44, component::DAC7678::VOUTA);
            register_resource<BiasRegulator>("BIAS_2", U44, component::DAC7678::VOUTC);
            register_resource<BiasRegulator>("BIAS_3", U44, component::DAC7678::VOUTE);
            register_resource<BiasRegulator>("BIAS_4", U44, component::DAC7678::VOUTG);
            register_resource<BiasRegulator>("BIAS_5", U44, component::DAC7678::VOUTB);
            register_resource<BiasRegulator>("BIAS_6", U44, component::DAC7678::VOUTD);
            register_resource<BiasRegulator>("BIAS_7", U44, component::DAC7678::VOUTF);
            register_resource<BiasRegulator>("BIAS_8", U44, component::DAC7678::VOUTH);

            register_resource<BiasRegulator>("BIAS_9", U46, component::DAC7678::VOUTA);
            register_resource<BiasRegulator>("BIAS_10", U46, component::DAC7678::VOUTC);
            register_resource<BiasRegulator>("BIAS_11", U46, component::DAC7678::VOUTE);
            register_resource<BiasRegulator>("BIAS_12", U46, component::DAC7678::VOUTG);
            register_resource<BiasRegulator>("BIAS_13", U46, component::DAC7678::VOUTB);
            register_resource<BiasRegulator>("BIAS_14", U46, component::DAC7678::VOUTD);
            register_resource<BiasRegulator>("BIAS_15", U46, component::DAC7678::VOUTF);
            register_resource<BiasRegulator>("BIAS_16", U46, component::DAC7678::VOUTH);

            register_resource<BiasRegulator>("BIAS_17", U45, component::DAC7678::VOUTA);
            register_resource<BiasRegulator>("BIAS_18", U45, component::DAC7678::VOUTC);
            register_resource<BiasRegulator>("BIAS_19", U45, component::DAC7678::VOUTE);
            register_resource<BiasRegulator>("BIAS_20", U45, component::DAC7678::VOUTG);
            register_resource<BiasRegulator>("BIAS_21", U45, component::DAC7678::VOUTB);
            register_resource<BiasRegulator>("BIAS_22", U45, component::DAC7678::VOUTD);
            register_resource<BiasRegulator>("BIAS_23", U45, component::DAC7678::VOUTF);
            register_resource<BiasRegulator>("BIAS_24", U45, component::DAC7678::VOUTH);

            register_resource<BiasRegulator>("BIAS_25", U48, component::DAC7678::VOUTA);
            register_resource<BiasRegulator>("BIAS_26", U48, component::DAC7678::VOUTC);
            register_resource<BiasRegulator>("BIAS_27", U48, component::DAC7678::VOUTE);
            register_resource<BiasRegulator>("BIAS_28", U48, component::DAC7678::VOUTG);
            register_resource<BiasRegulator>("BIAS_29", U48, component::DAC7678::VOUTB);
            register_resource<BiasRegulator>("BIAS_30", U48, component::DAC7678::VOUTD);
            register_resource<BiasRegulator>("BIAS_31", U48, component::DAC7678::VOUTF);
            register_resource<BiasRegulator>("BIAS_32", U48, component::DAC7678::VOUTH);

            // Slow ADC input channels:
            register_resource<ADCInput>("VOL_IN_1", U77, component::ADS7828::CHO);
            register_resource<ADCInput>("VOL_IN_2", U77, component::ADS7828::CH1);
            register_resource<ADCInput>("VOL_IN_3", U77, component::ADS7828::CH2);
            register_resource<ADCInput>("VOL_IN_4", U77, component::ADS7828::CH3);
            register_resource<ADCInput>("VOL_IN_5", U77, component::ADS7828::CH4);
            register_resource<ADCInput>("VOL_IN_6", U77, component::ADS7828::CH5);
            register_resource<ADCInput>("VOL_IN_7", U77, component::ADS7828::CH6);
            register_resource<ADCInput>("VOL_IN_8", U77, component::ADS7828::CH7);

            // CMOS I/O voltage levels
            register_resource<CMOSLevels>("CMOS_IN",
                                          U87,
                                          std::vector<component::DAC7678::Channel> {component::DAC7678::VOUTA,
                                                                                    component::DAC7678::VOUTB,
                                                                                    component::DAC7678::VOUTC,
                                                                                    component::DAC7678::VOUTD});
            register_resource<CMOSLevels>(
                "CMOS_OUT",
                U87,
                std::vector<component::DAC7678::Channel> {component::DAC7678::VOUTE, component::DAC7678::VOUTG});

            register_resource<BiasRegulator>("CMOS_IN_1_TO_4", U87, component::DAC7678::VOUTC);
            register_resource<BiasRegulator>("CMOS_IN_5_TO_8", U87, component::DAC7678::VOUTA);
            register_resource<BiasRegulator>("CMOS_IN_9_TO_12", U87, component::DAC7678::VOUTB);
            register_resource<BiasRegulator>("CMOS_IN_13_TO_14", U87, component::DAC7678::VOUTD);
            register_resource<BiasRegulator>("CMOS_OUT_1_TO_4", U87, component::DAC7678::VOUTE);
            register_resource<BiasRegulator>("CMOS_OUT_5_TO_8", U87, component::DAC7678::VOUTG);

            // Injection voltage bias
            register_resource<BiasRegulator>("INJ_1", U49, component::DAC7678::VOUTF);
            register_resource<BiasRegulator>("INJ_2", U49, component::DAC7678::VOUTE);
            register_resource<BiasRegulator>("INJ_3", U49, component::DAC7678::VOUTC);
            register_resource<BiasRegulator>("INJ_4", U49, component::DAC7678::VOUTA);
        }

        virtual ~Carboard() = default;

    private:
        // Board components
        component::Si570 USRCLK;
        component::Si5345 SI;
        component::TMP101 U30;
        component::PCA9539 U15, U31;
        component::DAC7678 U44, U45, U46, U47, U48, U49, U50, U87;
        component::INA226 U52, U53, U54, U55, U56, U57, U58, U59;
        component::ADS7828 U77;
        component::EEPROM24LC32A U78;
    };
} // namespace peary::board::carboard
  

Updated on 2025-11-14 at 11:31:23 +0100