From 8b95182b08fe6006eecd5a79d88067932667455d Mon Sep 17 00:00:00 2001 From: Niklas Eiling Date: Tue, 9 Jan 2024 17:07:21 +0100 Subject: [PATCH] automatically configure and test Dino based on hwdef json this currently requires manually adding the mapping of Dinos to i2c buses in the fpga json. Signed-off-by: Niklas Eiling --- .../vc707-xbar-pcie-dino.json | 2 + fpga/include/villas/fpga/ips/dino.hpp | 38 ++++++++++++ fpga/lib/ips/dino.cpp | 59 ++++++++++++++++--- 3 files changed, 90 insertions(+), 9 deletions(-) diff --git a/fpga/etc/vc707-xbar-pcie-dino/vc707-xbar-pcie-dino.json b/fpga/etc/vc707-xbar-pcie-dino/vc707-xbar-pcie-dino.json index 42e6683c2..89d1e7780 100644 --- a/fpga/etc/vc707-xbar-pcie-dino/vc707-xbar-pcie-dino.json +++ b/fpga/etc/vc707-xbar-pcie-dino/vc707-xbar-pcie-dino.json @@ -1014,6 +1014,7 @@ }, "dino_dinoif_dac_0": { "vlnv": "xilinx.com:module_ref:dinoif_dac:1.0", + "i2c_channel": 1, "parameters": { "component_name": "design_1_dinoif_dac_0_0", "edk_iptype": "PERIPHERAL" @@ -1028,6 +1029,7 @@ }, "dino_dinoif_fast_0": { "vlnv": "xilinx.com:module_ref:dinoif_fast:1.0", + "i2c_channel": 0, "parameters": { "component_name": "design_1_dinoif_fast_0_0", "edk_iptype": "PERIPHERAL" diff --git a/fpga/include/villas/fpga/ips/dino.hpp b/fpga/include/villas/fpga/ips/dino.hpp index f31453eb7..b0f7d977b 100644 --- a/fpga/include/villas/fpga/ips/dino.hpp +++ b/fpga/include/villas/fpga/ips/dino.hpp @@ -18,6 +18,7 @@ namespace ip { class Dino : public Node { public: + friend class DinoFactory; union IoextPorts { struct __attribute__((packed)) { bool clk_dir : 1; @@ -52,6 +53,7 @@ public: Dino(); virtual ~Dino(); + virtual bool init() override; void setI2c(std::shared_ptr i2cdev, uint8_t i2c_channel) { this->i2cdev = i2cdev; this->i2c_channel = i2c_channel; @@ -75,6 +77,7 @@ public: protected: std::shared_ptr i2cdev; uint8_t i2c_channel; + bool configDone; IoextPorts getIoextDir(); IoextPorts getIoextOut(); @@ -98,6 +101,41 @@ public: Gain getGain(); }; +class DinoFactory : NodeFactory { +public: + virtual std::string getDescription() const { return "Dino Analog I/O"; } + +protected: + virtual void parse(Core &ip, json_t *json) override; +}; + +class DinoAdcFactory : DinoFactory { +public: + virtual std::string getName() const { return "dinoAdc"; } + +private: + virtual Vlnv getCompatibleVlnv() const { + return Vlnv("xilinx.com:module_ref:dinoif_fast:"); + } + Core *make() const { return new DinoAdc; }; +}; + +class DinoDacFactory : DinoFactory { +public: + virtual std::string getName() const { return "dinoDac"; } + +private: + virtual Vlnv getCompatibleVlnv() const { + return Vlnv("xilinx.com:module_ref:dinoif_dac:"); + } + Core *make() const { return new DinoDac; }; +}; + } // namespace ip } // namespace fpga } // namespace villas + +#ifndef FMT_LEGACY_OSTREAM_FORMATTER +template <> +class fmt::formatter : public fmt::ostream_formatter {}; +#endif diff --git a/fpga/lib/ips/dino.cpp b/fpga/lib/ips/dino.cpp index f7b394f63..33d075bd2 100644 --- a/fpga/lib/ips/dino.cpp +++ b/fpga/lib/ips/dino.cpp @@ -9,14 +9,35 @@ #include +#include #include using namespace villas::fpga::ip; -Dino::Dino() : Node(), i2cdev(nullptr), i2c_channel(0) {} +Dino::Dino() : Node(), i2cdev(nullptr), i2c_channel(0), configDone(false) {} Dino::~Dino() {} +bool Dino::init() { + if (!configDone) { + logger->error("Dino configuration not done yet"); + throw RuntimeError("Dino configuration not done yet"); + } + if (i2cdev == nullptr) { + i2cdev = std::dynamic_pointer_cast( + card->lookupIp(fpga::Vlnv("xilinx.com:ip:axi_iic:"))); + if (i2cdev == nullptr) { + logger->error("No I2C found on FPGA"); + throw RuntimeError( + "Dino requires and I2C device but none was found on FPGA"); + } else { + logger->debug("Found I2C on FPGA"); + } + } + configureHardware(); + return true; +} + void Dino::setIoextDir(IoextPorts ports) { if (i2cdev == nullptr) { throw RuntimeError("I2C device not set"); @@ -80,6 +101,10 @@ DinoAdc::DinoAdc() : Dino() {} DinoAdc::~DinoAdc() {} void DinoAdc::configureHardware() { + if (!configDone) { + logger->error("ADC configuration not done yet"); + throw RuntimeError("ADC configuration not done yet"); + } if (i2cdev == nullptr) { throw RuntimeError("I2C device not set"); } @@ -117,6 +142,10 @@ DinoDac::DinoDac() : Dino() {} DinoDac::~DinoDac() {} void DinoDac::configureHardware() { + if (!configDone) { + logger->error("DAC configuration not done yet"); + throw RuntimeError("DAC configuration not done yet"); + } if (i2cdev == nullptr) { throw RuntimeError("I2C device not set"); } @@ -169,12 +198,24 @@ Dino::Gain DinoDac::getGain() { return ret; } -static char n_adc[] = "DINO ADC"; -static char d_adc[] = "DINO analog to digital converter"; -static char v_adc[] = "xilinx.com:module_ref:dinoif_fast:"; -static NodePlugin f_adc; +void DinoFactory::parse(Core &ip, json_t *cfg) { + NodeFactory::parse(ip, cfg); -static char n_dac[] = "DINO DAC"; -static char d_dac[] = "DINO digital to analog converter"; -static char v_dac[] = "xilinx.com:module_ref:dinoif_dac:"; -static NodePlugin f_dac; + auto &dino = dynamic_cast(ip); + json_error_t err; + int i2c_channel; + int ret = + json_unpack_ex(cfg, &err, 0, "{ s: i }", "i2c_channel", &i2c_channel); + if (ret != 0) { + throw ConfigError(cfg, err, "", "Failed to parse Dino configuration"); + } + if (i2c_channel < 0 || i2c_channel >= 8) { + throw ConfigError(cfg, err, "", "Invalid I2C channel"); + } + dino.i2c_channel = static_cast(i2c_channel); + + dino.configDone = true; +} + +static DinoAdcFactory fAdc; +static DinoDacFactory fDac;