diff --git a/etc/examples/nodes/fpga.conf b/etc/examples/nodes/fpga.conf index 697e2a8df..529caa77d 100644 --- a/etc/examples/nodes/fpga.conf +++ b/etc/examples/nodes/fpga.conf @@ -19,8 +19,9 @@ fpgas = { nodes = { fpga_0 = { type = "fpga", - card = "vc707" - connect = ["0->3", "3->dma", "0<-dma"] + card = "vc707", + connect = ["0->3", "3->dma", "0<-dma"], + timestep = 10e-3, } } diff --git a/fpga/src/villas-fpga-ctrl.cpp b/fpga/src/villas-fpga-ctrl.cpp index b2363e401..b4c7076b9 100644 --- a/fpga/src/villas-fpga-ctrl.cpp +++ b/fpga/src/villas-fpga-ctrl.cpp @@ -244,6 +244,14 @@ int main(int argc, char *argv[]) { } } } + auto reg = std::dynamic_pointer_cast( + card->lookupIp(fpga::Vlnv("xilinx.com:module_ref:registerif:"))); + + if (reg != nullptr && + card->lookupIp(fpga::Vlnv("xilinx.com:module_ref:dinoif_fast:"))) { + fpga::ip::DinoAdc::setRegisterConfigTimestep(reg, 10e-3); + } + if (writeToStdout || readFromStdin) { auto dma = std::dynamic_pointer_cast( card->lookupIp(fpga::Vlnv("xilinx.com:ip:axi_dma:"))); diff --git a/include/villas/nodes/fpga.hpp b/include/villas/nodes/fpga.hpp index a124efca3..408334f50 100644 --- a/include/villas/nodes/fpga.hpp +++ b/include/villas/nodes/fpga.hpp @@ -45,6 +45,15 @@ protected: // Improves read/write latency by approx. 40%. bool lowLatencyMode; + // This sets the requested timestep in the FPGA timestep generation IP. + // The value is interpreted as seconds (i.e. 10e-3 is a timestep of 10ms). + // It is used to program the Register IP that in turn generates conversions + // of DinoAdc. This means that this setting represents the inverse of the + // Dino sampling rate. + // The setting must be programmed using DinoAdc::setRegisterConfigTimestep, + // which FpgaNode does in prepare only if a Register and a DinoAdc is present. + double timestep; + // State std::shared_ptr card; std::shared_ptr dma; diff --git a/lib/nodes/fpga.cpp b/lib/nodes/fpga.cpp index c365436e9..853d7ab65 100644 --- a/lib/nodes/fpga.cpp +++ b/lib/nodes/fpga.cpp @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include @@ -34,7 +36,7 @@ static std::shared_ptr vfioContainer; FpgaNode::FpgaNode(const uuid_t &id, const std::string &name) : Node(id, name), cardName(""), connectStrings(), lowLatencyMode(false), - card(nullptr), dma(), blockRx(), blockTx() {} + timestep(10e-3), card(nullptr), dma(), blockRx(), blockTx() {} FpgaNode::~FpgaNode() {} @@ -67,6 +69,17 @@ int FpgaNode::prepare() { parsedConnectString.configCrossBar(card); } + auto reg = std::dynamic_pointer_cast( + card->lookupIp(fpga::Vlnv("xilinx.com:module_ref:registerif:"))); + + if (reg != nullptr && + card->lookupIp(fpga::Vlnv("xilinx.com:module_ref:dinoif_fast:"))) { + // constexpr double sampleRate = 20e3; // We want to achieve a timestep of 50us + fpga::ip::DinoAdc::setRegisterConfigTimestep(reg, 10e-3); + } else { + logger->warn("No DinoAdc or no Register found on FPGA."); + } + dma = std::dynamic_pointer_cast( card->lookupIp(fpga::Vlnv("xilinx.com:ip:axi_dma:"))); if (dma == nullptr) { @@ -106,9 +119,10 @@ int FpgaNode::parse(json_t *json) { vfioContainer = std::make_shared(); } - ret = json_unpack_ex(json, &err, 0, "{ s: o, s?: o, s?: b, s?: b}", "card", - &jsonCard, "connect", &jsonConnectStrings, - "lowLatencyMode", &lowLatencyMode); + ret = + json_unpack_ex(json, &err, 0, "{ s: o, s?: o, s?: b, s?: b, s?: f}", + "card", &jsonCard, "connect", &jsonConnectStrings, + "lowLatencyMode", &lowLatencyMode, "timestep", ×tep); if (ret) { throw ConfigError(json, err, "node-config-fpga", "Failed to parse configuration of node {}", @@ -167,20 +181,20 @@ const std::string &FpgaNode::getDetails() { return details; } -int FpgaNode::check() { return 0; } +int FpgaNode::check() { return Node::check(); } int FpgaNode::start() { - if (getInputSignalsMaxCount() * sizeof(float) > blockRx->getSize()) { - logger->error("Input signals exceed block size."); - throw villas ::RuntimeError("Input signals exceed block size."); + if (getOutputSignalsMaxCount() * sizeof(float) > blockRx->getSize()) { + logger->error("Output signals exceed block size."); + throw villas ::RuntimeError("Output signals exceed block size."); } if (lowLatencyMode) { dma->readScatterGatherPrepare(*blockRx, blockRx->getSize()); - if (getInputSignalsMaxCount() != 0) { - dma->writeScatterGatherPrepare(*blockTx, - getInputSignalsMaxCount() * sizeof(float)); + if (getOutputSignalsMaxCount() != 0) { + dma->writeScatterGatherPrepare(*blockTx, getOutputSignalsMaxCount() * + sizeof(float)); } else { - logger->warn("No input signals defined. Not preparing write buffer - " + logger->warn("No output signals defined. Not preparing write buffer - " "writes will not work."); } } @@ -212,7 +226,8 @@ int FpgaNode::fastWrite(Sample *smps[], unsigned cnt) { mem[i] = smp->data[i].i; } } - + logger->info("Writing sample: {}, {}, {:#x}", smp->data[0].f, + smp->signals->getByIndex(0)->type, mem[0]); dma->writeScatterGatherFast(); auto written = dma->writeScatterGatherPoll() / sizeof(float); // The number of samples written @@ -242,6 +257,7 @@ int FpgaNode::fastRead(Sample *smps[], unsigned cnt) { smp->length = 0; for (unsigned i = 0; i < MIN(read / sizeof(float), smp->capacity); i++) { smp->data[i].f = static_cast(mem[i]); + // logger->info("Read sample: {}", smp->data[i].f); smp->length++; }