diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt
index bc9883747a0e9aad120c691a3071046e81d13912..a2a052fa4026f62246d4be605c6a50c2217bf65a 100644
--- a/algo/CMakeLists.txt
+++ b/algo/CMakeLists.txt
@@ -154,6 +154,8 @@ set(SRCS
   qa/QaData.cxx
   qa/RecoGeneralQa.cxx
   qa/QaManager.cxx
+  qa/hitfind/BmonHitfindQa.cxx
+  qa/hitfind/BmonHitfindQaParameters.cxx
   qa/unpack/StsDigiQa.cxx
   ca/TrackingSetup.cxx
   ca/TrackingChain.cxx
@@ -191,6 +193,7 @@ target_include_directories(Algo
          ${CMAKE_CURRENT_SOURCE_DIR}/detectors
          ${CMAKE_CURRENT_SOURCE_DIR}/qa
          ${CMAKE_CURRENT_SOURCE_DIR}/qa/unpack
+         ${CMAKE_CURRENT_SOURCE_DIR}/qa/hitfind
          ${CMAKE_CURRENT_SOURCE_DIR}/kf
          ${CMAKE_CURRENT_SOURCE_DIR}/kf/core
          ${CMAKE_CURRENT_SOURCE_DIR}/kf/core/utils
diff --git a/algo/ca/qa/CaQa.h b/algo/ca/qa/CaQa.h
index 655d6fa50b16a9dac1133223ebafb56abeef08e7..1c42b60562f19c5adf5274c045971fe9bda330bf 100644
--- a/algo/ca/qa/CaQa.h
+++ b/algo/ca/qa/CaQa.h
@@ -54,7 +54,7 @@ namespace cbm::algo::ca
     static constexpr HitSetArray_t<EHitSet> kHitSets = {EHitSet::Input, EHitSet::Used};
 
    public:
-    /// \brief Default destructor
+    /// \brief Constructor
     /// \param pManager  Pointer to the QA manager
     /// \param name      Name of the QA (directory)
     Qa(const std::unique_ptr<qa::Manager>& pManager, std::string_view name) : qa::TaskHeader(pManager, name) {}
diff --git a/algo/detectors/bmon/Calibrate.cxx b/algo/detectors/bmon/Calibrate.cxx
index 1a2a6af79d13a522eaf08ffcf6072ccefdc70852..d5519854902605e3c84e77f584324d3811c88d04 100644
--- a/algo/detectors/bmon/Calibrate.cxx
+++ b/algo/detectors/bmon/Calibrate.cxx
@@ -77,8 +77,8 @@ Calibrate::resultType Calibrate::operator()(gsl::span<const CbmBmonDigi> digiIn)
   // --- Output data
   resultType result = {};
 
-  auto& calDigiOut = result.first;
-  auto& monitor    = result.second;
+  auto& calDigiOut = std::get<0>(result);
+  auto& monitor    = std::get<1>(result);
   calDigiOut.reserve(digiIn.size());
 
   // Reset the channel dead time
diff --git a/algo/detectors/bmon/Calibrate.h b/algo/detectors/bmon/Calibrate.h
index 0e602e6b4cc1b626c768b006c001c541aef5b8db..644fd203200dbceeac0402248b5cf3a2943be3c3 100644
--- a/algo/detectors/bmon/Calibrate.h
+++ b/algo/detectors/bmon/Calibrate.h
@@ -30,7 +30,7 @@ namespace cbm::algo::bmon
   /// \brief Algorithm to calibrate BMon digis
   class Calibrate {
    public:
-    using resultType = std::pair<std::vector<CbmBmonDigi>, CalibrateMonitorData>;
+    using resultType = std::tuple<std::vector<CbmBmonDigi>, CalibrateMonitorData>;
 
     /// \brief Constructor
     /// \param params  Calibration parameters
diff --git a/algo/detectors/bmon/Clusterizer.cxx b/algo/detectors/bmon/Clusterizer.cxx
index 2d48416e35b526462ee7b8ef9bcb2d15086015cf..d3a8e3d4abf18a8a9e1e727606fd08a187afdf88 100644
--- a/algo/detectors/bmon/Clusterizer.cxx
+++ b/algo/detectors/bmon/Clusterizer.cxx
@@ -67,6 +67,7 @@ Clusterizer::Output_t Clusterizer::operator()(const Clusterizer::Input_t& digis)
     hits.emplace_back(fParams.fAddress, itLast->first);
     digiIndices.emplace_back(itLast->second);
   }
+
   return res;
 }
 
diff --git a/algo/detectors/bmon/Hitfind.cxx b/algo/detectors/bmon/Hitfind.cxx
index b1e6794c8e0291231e2fb2e87d51d6ce92f0bb38..d39a46f6c4bf9faf4bfbe2425557ef85ba02664a 100644
--- a/algo/detectors/bmon/Hitfind.cxx
+++ b/algo/detectors/bmon/Hitfind.cxx
@@ -86,6 +86,7 @@ Hitfind::Output_t Hitfind::operator()(gsl::span<CbmBmonDigi> digisIn, uint32_t i
   // Distribute digis over diamonds, apply cuts on this level (maybe the Calibrator is a more proper place for it)
   size_t nDiamonds  = algoPerThread.size();
   auto vDigiStorage = std::vector<Clusterizer::Input_t>(nDiamonds, Clusterizer::Input_t(0));
+
   for (int32_t iDigi = 0; iDigi < static_cast<int32_t>(digisIn.size()); ++iDigi) {
     const auto& digi = digisIn[iDigi];
     size_t iDiamond  = GetDiamondIndex(digi.GetAddress());
diff --git a/algo/detectors/bmon/HitfindSetup.h b/algo/detectors/bmon/HitfindSetup.h
index c98cc163ff616f0f0e0b8a55158ea224ebf9cbb6..c958cbc17ca2ffcdc2f5027a42f3e6f8f09b1e22 100644
--- a/algo/detectors/bmon/HitfindSetup.h
+++ b/algo/detectors/bmon/HitfindSetup.h
@@ -7,6 +7,7 @@
 /// \since  06.02.2025
 /// \author Sergei Zharko <s.zharko@gsi.de>
 
+#pragma once
 
 #include "Definitions.h"
 #include "yaml/Property.h"
diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx
index 5b2698cb3f2f0c2928165baaa30abfcf298040fe..8460ea28bf34fa71071601370839602433199058 100644
--- a/algo/global/Reco.cxx
+++ b/algo/global/Reco.cxx
@@ -24,6 +24,7 @@
 #include "evbuild/Config.h"
 #include "much/Unpack.h"
 #include "qa/QaManager.h"
+#include "qa/hitfind/BmonHitfindQa.h"
 #include "rich/Unpack.h"
 #include "sts/ChannelMaskSet.h"
 #include "sts/HitfinderChain.h"
@@ -217,6 +218,12 @@ void Reco::Init(const Options& opts)
 
     auto hitfindSetup = yaml::ReadFromFile<bmon::HitfindSetup>(opts.ParamsDir() / parFiles.bmon.hitfinder);
     fBmonHitFinder    = std::make_unique<bmon::Hitfind>(hitfindSetup);
+
+    if (fQaManager != nullptr && Opts().Has(QaStep::RecoBmon)) {
+      fBmonHitFinderQa = std::make_unique<bmon::HitfindQa>(fQaManager, "BmonHitfindEvent");
+      fBmonHitFinderQa->InitParameters(calibSetup, hitfindSetup);
+      fBmonHitFinderQa->Init();
+    }
   }
 
   // TOF Hitfinder
@@ -236,7 +243,7 @@ void Reco::Init(const Options& opts)
 
   // Tracking
   if (Opts().Has(Step::Tracking)) {
-    if (Opts().Has(QaStep::Tracking)) {
+    if (fQaManager != nullptr && Opts().Has(QaStep::Tracking)) {
       fTracking = std::make_unique<TrackingChain>(fQaManager, "CaTimeslice");
     }
     else {
@@ -389,24 +396,18 @@ RecoResults Reco::Run(const fles::Timeslice& ts)
     // ***** DEBUG: BEGIN
     if constexpr (0) {
       int nEvents = events.size();
-      size_t nBmonHitsOneChannel{0};
-      size_t nBmonHitsTwoChannels{0};
       for (int iE = 0; iE < nEvents; ++iE) {
         const auto& event = events[iE];
         // Calibrate TOF digis:
         auto [bmonDigis, bmonCalMonitor]         = (*fBmonCalibrator)(event.fBmon);
-        auto [bmonHits, hitmonitor, digiindices] = (*fBmonHitFinder)(bmonDigis);
-        for (const auto& hit : bmonHits.Data()) {
-          if (hit.GetNofChannels() == 1) {
-            ++nBmonHitsOneChannel;
-          }
-          else {
-            ++nBmonHitsTwoChannels;
-          }
+        auto [bmonHits, hitmonitor, digiIndices] = (*fBmonHitFinder)(bmonDigis);
+        if (fBmonHitFinderQa != nullptr) {
+          fBmonHitFinderQa->RegisterDigis(&bmonDigis);
+          fBmonHitFinderQa->RegisterHits(&bmonHits);
+          fBmonHitFinderQa->RegisterDigiIndices(&digiIndices);
+          fBmonHitFinderQa->Exec();
         }
       }
-      L_(info) << "!!!! BMON hits with two channels: " << nBmonHitsTwoChannels << " / "
-               << (nBmonHitsTwoChannels + nBmonHitsOneChannel);
     }
     // ***** DEBUG: END
 
diff --git a/algo/global/Reco.h b/algo/global/Reco.h
index 19027c8368b9fe496282f40eca52eaff22f339d6..6182decdad9d289e7a654aabbb6b5db8650efe29 100644
--- a/algo/global/Reco.h
+++ b/algo/global/Reco.h
@@ -29,6 +29,7 @@ namespace cbm::algo
     class Unpack;
     class Calibrate;
     class Hitfind;
+    class HitfindQa;
   }
 
   namespace much
@@ -150,6 +151,7 @@ namespace cbm::algo
     std::unique_ptr<bmon::Unpack> fBmonUnpack;
     std::unique_ptr<bmon::Calibrate> fBmonCalibrator;
     std::unique_ptr<bmon::Hitfind> fBmonHitFinder;
+    std::unique_ptr<bmon::HitfindQa> fBmonHitFinderQa;
 
     // MUCH
     std::unique_ptr<much::Unpack> fMuchUnpack;
diff --git a/algo/qa/PadConfig.h b/algo/qa/PadConfig.h
index 4d6ac5376c121a618601111ff3aa1d6d07deba09..104b2144263b06834952557d14d3b30d21e6197a 100644
--- a/algo/qa/PadConfig.h
+++ b/algo/qa/PadConfig.h
@@ -43,6 +43,15 @@ namespace cbm::algo::qa
     {
     }
 
+    /// \brief  Constructor from a single histogram
+    /// \tparam Hist  Histogram class
+    /// \param  hist  Histogram object
+    /// \param  opt   Draw options for the histogram
+    template<class Hist>
+    PadConfig(const Hist* hist, std::string_view opt)
+    {
+      RegisterHistogram(hist, opt);
+    }
 
     /// \brief Copy constructor
     PadConfig(const PadConfig&) = default;
@@ -104,11 +113,11 @@ namespace cbm::algo::qa
     std::string ToString() const;
 
    private:
-    bool fbGridX = false;  ///< Grid flag for x-axis
-    bool fbGridY = false;  ///< Grid flag for y-axis
-    bool fbLogX  = false;  ///< Log flag for x-axis
-    bool fbLogY  = false;  ///< Log flag for y-axis
-    bool fbLogZ  = false;  ///< Log flag for z-axis
+    bool fbGridX{false};  ///< Grid flag for x-axis
+    bool fbGridY{false};  ///< Grid flag for y-axis
+    bool fbLogX{false};   ///< Log flag for x-axis
+    bool fbLogY{false};   ///< Log flag for y-axis
+    bool fbLogZ{false};   ///< Log flag for z-axis
 
     std::vector<std::pair<std::string, std::string>> fvObjectList;  ///< List of objects on the pad
   };
diff --git a/algo/qa/QaTaskHeader.h b/algo/qa/QaTaskHeader.h
index ca41383152a066fd98b79293f874428cd53fb350..ceb03e5ad457c9b6ceecb1145c7a5f4c15f262b9 100644
--- a/algo/qa/QaTaskHeader.h
+++ b/algo/qa/QaTaskHeader.h
@@ -24,7 +24,8 @@ namespace cbm::algo::qa
     /// \param pManager a QA-manager
     /// \param name A name of the task (histograms directory)
     TaskHeader(const std::unique_ptr<Manager>& pManager, std::string_view name)
-      : fpData(pManager != nullptr ? pManager->GetData() : nullptr)
+      : fsName(name)
+      , fpData(pManager != nullptr ? pManager->GetData() : nullptr)
     {
       if (fpData != nullptr) {
         fpData->RegisterNewTask(name);
@@ -52,6 +53,9 @@ namespace cbm::algo::qa
     /// the fpData instance is not defined, and no actions on the task should be performed
     bool IsActive() const { return static_cast<bool>(fpData != nullptr); }
 
+    /// \brief Gets name of the task
+    const std::string& GetTaskName() { return fsName; }
+
    protected:
     /// \brief Adds a canvas configuration
     /// \param canvas  A CanvasConfig object
@@ -68,6 +72,7 @@ namespace cbm::algo::qa
     }
 
    private:
+    std::string fsName{};                   ///< Name of the task
     std::shared_ptr<Data> fpData{nullptr};  ///< An instance of the QA data (shared between different tasks)
   };
 }  // namespace cbm::algo::qa
diff --git a/algo/qa/hitfind/BmonHitfindQa.cxx b/algo/qa/hitfind/BmonHitfindQa.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..0bf088900f35ef7f55b6ce59f311bda818dee011
--- /dev/null
+++ b/algo/qa/hitfind/BmonHitfindQa.cxx
@@ -0,0 +1,112 @@
+/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   BmonHitfindQa.cxx
+/// \brief  A BMON hitfinder QA (implementation)
+/// \since  09.02.2025
+/// \author Sergei Zharko <s.zharko@gsi.de>
+
+#include "qa/hitfind/BmonHitfindQa.h"
+
+#include "CbmBmonDigi.h"
+#include "CbmTofAddress.h"
+#include "bmon/Hit.h"
+#include "qa/Histogram.h"
+
+#include <fmt/format.h>
+
+using cbm::algo::bmon::HitfindQa;
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void HitfindQa::Init()
+try {
+  using fmt::format;
+  if (!IsActive()) {
+    return;
+  }
+
+  size_t nDiamonds = fParameters.diamonds.size();
+  if (nDiamonds < 1) {
+    throw std::runtime_error("parameters were not initialized. Please, provide the configuration using the function "
+                             "HitfindQa::InitParameters(calSetup, hitSetup)");
+  }
+
+  fvphDigiOccupVsChan.resize(nDiamonds, nullptr);
+  fvphDigiChargeVsChan.resize(nDiamonds, nullptr);
+  fvphHitNofChan.resize(nDiamonds, nullptr);
+  fvphHitTimeDiff.resize(nDiamonds, nullptr);
+
+  for (size_t iD = 0; iD < nDiamonds; ++iD) {
+    const auto& diamondPar = fParameters.diamonds[iD];
+    int nCh                = diamondPar.nChannels;
+    auto sDN               = format("_diamond_{:#08x}", diamondPar.address);  // diamond suffix
+
+    // Histograms initialisation
+    /* clang-format off */
+    fvphDigiOccupVsChan[iD] = MakeObj<qa::H1D>(
+      format("bmon_digi_occup_channel{}", sDN),
+      format("BMON-{} digi occupancy vs. channel;channel;counts", iD), 
+      nCh, -0.5, nCh - 0.5);
+    fvphDigiChargeVsChan[iD] = MakeObj<qa::H2D>(
+      format("bmon_digi_charge_channel{}", sDN),
+      format("BMON-{} digi charge vs. channel;channel;charge;counts", iD),
+      nCh, -0.5, nCh - 0.5, kChrgB, kChrgL, kChrgU);
+    fvphHitNofChan[iD]       = MakeObj<qa::H1D>(
+      format("bmon_hit_nChannels{}", sDN),
+      format("BMON-{} hit number of channels;N_{{chan}};counts", iD), 
+      2, 0.5, 2.5);
+    fvphHitTimeDiff[iD]      = MakeObj<qa::H1D>(
+      format("bmon_hit_time_diff{}", sDN),
+      format("BMON-{} digi time difference in a hit formed from two digis;#Delta t_{{digi}} [ns];counts", iD), 
+      kDtimeB, kDtimeL, kDtimeU);
+    /* clang-format on */
+
+    // Canvas initialization
+    auto cName = format("{}/bmon{}", GetTaskName(), sDN);
+    auto cTitl = format("BMON-{}", iD);
+    auto canv  = qa::CanvasConfig(cName, cTitl, 2, 2);
+    canv.AddPadConfig(qa::PadConfig(fvphDigiOccupVsChan[iD], "hist"));   // (0,0)
+    canv.AddPadConfig(qa::PadConfig(fvphDigiChargeVsChan[iD], "colz"));  // (1,0)
+    canv.AddPadConfig(qa::PadConfig(fvphHitNofChan[iD], "hist"));        // (0,1)
+    canv.AddPadConfig(qa::PadConfig(fvphHitTimeDiff[iD], "hist"));       // (1,1)
+    AddCanvasConfig(canv);
+  }
+}
+catch (const std::exception& err) {
+  L_(fatal) << "bmon::HitfindQa: initialization failed. Reason: " << err.what();
+  throw std::runtime_error("bmon::HitfindQa initialization failure");
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void HitfindQa::Exec()
+{
+  if (!IsActive()) {
+    return;
+  }
+
+  // Fill digi distributions
+  for (const auto& digi : *fpDigis) {
+    size_t iDiamond = fParameters.GetDiamondIndex(digi.GetAddress());
+    int32_t chan    = digi.GetChannel();
+    fvphDigiOccupVsChan[iDiamond]->Fill(chan);
+    fvphDigiChargeVsChan[iDiamond]->Fill(chan, digi.GetCharge());
+  }
+
+  // Fill hit distributions
+  const auto& hits = fpHits->Data();
+  for (size_t iH = 0; iH < hits.size(); ++iH) {
+    const auto& hit = hits[iH];
+    size_t iDiamond = fParameters.GetDiamondIndex(hit.GetAddress());
+    int nChannels   = hit.GetNofChannels();
+    fvphHitNofChan[iDiamond]->Fill(nChannels);
+    if (nChannels == 2) {
+      int32_t iDigi     = (*fpDigiIndices)[iH];
+      const auto& digiF = (*fpDigis)[iDigi];
+      const auto& digiS = (*fpDigis)[iDigi + 1];
+      fvphHitTimeDiff[iDiamond]->Fill(digiS.GetTime() - digiF.GetTime());
+    }
+  }
+}
diff --git a/algo/qa/hitfind/BmonHitfindQa.h b/algo/qa/hitfind/BmonHitfindQa.h
new file mode 100644
index 0000000000000000000000000000000000000000..020f62fa821a2c8ec298c8aa758684aee023cc21
--- /dev/null
+++ b/algo/qa/hitfind/BmonHitfindQa.h
@@ -0,0 +1,112 @@
+/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   BmonHitfindQa.h
+/// \brief  A BMON hitfinder QA
+/// \since  07.02.2025
+/// \author Sergei Zharko <s.zharko@gsi.de>
+
+#pragma once
+
+#include "PODVector.h"
+#include "PartitionedVector.h"
+#include "qa/QaTaskHeader.h"
+#include "qa/hitfind/BmonHitfindQaParameters.h"
+
+class CbmBmonDigi;
+
+namespace cbm::algo
+{
+  namespace qa
+  {
+    class H1D;
+    class H2D;
+  }  // namespace qa
+
+  namespace bmon
+  {
+    class Hit;
+  }
+}  // namespace cbm::algo
+
+namespace cbm::algo::bmon
+{
+  /// \class HitfindQa
+  /// \brief A QA module for the BMON hit-finder
+  /// \param pManager  Pointer to the QA manager
+  /// \param name      Name of the QA (directory)
+  class HitfindQa : public qa::TaskHeader {
+   public:
+    /// \brief Constructor
+    /// \param pManager  Pointer to the QA manager
+    /// \param name      Name of the QA (directory)
+    HitfindQa(const std::unique_ptr<qa::Manager>& pManager, std::string_view name) : qa::TaskHeader(pManager, name) {}
+
+    /// \brief Constructor from the configuration object
+    /// \param config  QA configuration object
+    HitfindQa() = default;
+
+    /// \brief Copy constructor
+    HitfindQa(const HitfindQa&) = delete;
+
+    /// \brief Move constructor
+    HitfindQa(HitfindQa&&) = delete;
+
+    /// \brief Destructor
+    ~HitfindQa() = default;
+
+    /// \brief Copy assignment operator
+    HitfindQa& operator=(const HitfindQa&) = delete;
+
+    /// \brief Move assignment operator
+    HitfindQa& operator=(HitfindQa&&) = delete;
+
+    /// \brief Executes the task, fills the histograms
+    void Exec();
+
+    /// \brief Initialized the task
+    void Init();
+
+    /// \brief Initialisation of the parameters
+    void InitParameters(const CalibrateSetup& calSetup, const HitfindSetup& hitSetup)
+    {
+      fParameters = std::move(HitfindQaParameters(calSetup, hitSetup));
+    }
+
+    /// \brief Registers a sample of digis
+    /// \param pDigis  A pointer to a vector of digis
+    void RegisterDigis(const std::vector<CbmBmonDigi>* pDigis) { fpDigis = pDigis; }
+
+    /// \brief Registers a sample of hits
+    /// \param pHits  A pointer to a vector of hits
+    void RegisterHits(const PartitionedVector<bmon::Hit>* pHits) { fpHits = pHits; }
+
+    /// \brief Registers a sample of digi indices, used by hits
+    /// \param pDigiIndices  A pointer to a vector of digi indices
+    void RegisterDigiIndices(const PODVector<int32_t>* pDigiIndices) { fpDigiIndices = pDigiIndices; }
+
+   private:
+    //* Constants
+    static constexpr int kChrgB     = 150;   ///< charge scale: number of bins
+    static constexpr double kChrgL  = 0.;    ///< charge scale: lower bound
+    static constexpr double kChrgU  = 150.;  ///< charge scale: upper bound
+    static constexpr int kDtimeB    = 40;    ///< digi time difference: number of bins
+    static constexpr double kDtimeL = 0.;    ///< digi time difference: lower bound [ns]
+    static constexpr double kDtimeU = 2.0;   ///< digi time difference: upper bound [ns]
+
+    //* Parameters
+    HitfindQaParameters fParameters;  ///< Parameters of the hit finder QA
+
+    //* Data samples
+    const std::vector<CbmBmonDigi>* fpDigis{nullptr};     ///< Pointer to BMON digi sample
+    const PartitionedVector<bmon::Hit>* fpHits{nullptr};  ///< Pointer to BMON hit sample
+    const PODVector<int32_t>* fpDigiIndices{nullptr};     ///< Pointer to BMON digi indices, used by hits
+
+    //* Histograms
+    std::vector<qa::H1D*> fvphDigiOccupVsChan;   ///< Digi occupancy vs. channel [diamond]
+    std::vector<qa::H2D*> fvphDigiChargeVsChan;  ///< Digi charge vs channel [diamond]
+    std::vector<qa::H1D*> fvphHitNofChan;        ///< Hit  number of channels [diamond]
+    std::vector<qa::H1D*> fvphHitTimeDiff;       ///< Time difference of two digis in a hit [diamond]
+  };
+}  // namespace cbm::algo::bmon
diff --git a/algo/qa/hitfind/BmonHitfindQaParameters.cxx b/algo/qa/hitfind/BmonHitfindQaParameters.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..aa7f4aadce0f8e7cad631de165f789177a02c4c9
--- /dev/null
+++ b/algo/qa/hitfind/BmonHitfindQaParameters.cxx
@@ -0,0 +1,58 @@
+/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   BmonHitfindQaParameters.cxx
+/// \brief  A BMON hitfinder QA parameter configuration (implementation)
+/// \since  10.02.2025
+/// \author Sergei Zharko <s.zharko@gsi.de>
+
+#include "qa/hitfind/BmonHitfindQaParameters.h"
+
+#include "AlgoFairloggerCompat.h"
+#include "CbmTofAddress.h"
+
+using cbm::algo::bmon::CalibrateSetup;
+using cbm::algo::bmon::HitfindQaParameters;
+using cbm::algo::bmon::HitfindSetup;
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+HitfindQaParameters::HitfindQaParameters(const CalibrateSetup& calSetup, const HitfindSetup& hitSetup)
+{
+
+  this->selectionMask = calSetup.selectionMask;
+  if (this->selectionMask != hitSetup.selectionMask) {
+    throw std::runtime_error("Mismatch of the selection bitmask in the BMON CalibrateSetup and HitfindSetup configs");
+  }
+
+  auto nDiamonds = calSetup.diamonds.size();
+  if (nDiamonds != hitSetup.diamonds.size()) {
+    throw std::runtime_error("Mismatch of number of diamonds in the BMON CalibrateSetup and HitfindSetup configs");
+  }
+
+  if (nDiamonds > 1) {
+    while (!((this->selectionMask >> fSelectionBitsOffset) % 2)) {
+      ++fSelectionBitsOffset;
+    }
+  }
+
+  this->diamonds.resize(nDiamonds);
+  for (const auto& calDiamond : calSetup.diamonds) {
+    uint32_t address      = calDiamond.refAddress & ~CbmTofAddress::GetChannelIdBitmask();
+    auto& thisDiamond     = this->diamonds[GetDiamondIndex(address)];
+    thisDiamond.address   = address;
+    thisDiamond.nChannels = calDiamond.chanPar.size();
+  }
+
+  for (const auto& hitDiamond : hitSetup.diamonds) {
+    int32_t address   = hitDiamond.refAddress & ~CbmTofAddress::GetChannelIdBitmask();
+    auto& thisDiamond = this->diamonds[GetDiamondIndex(address)];
+    if (thisDiamond.address != address) {
+      throw std::runtime_error("Mismatch between diamond addresses in BMON CalibrateSetup and HitfindSetup configs");
+    }
+    thisDiamond.deadStrips  = hitDiamond.deadStrips;
+    thisDiamond.timeRes     = hitDiamond.timeRes;
+    thisDiamond.maxTimeDist = hitDiamond.maxTimeDist;
+  }
+}
diff --git a/algo/qa/hitfind/BmonHitfindQaParameters.h b/algo/qa/hitfind/BmonHitfindQaParameters.h
new file mode 100644
index 0000000000000000000000000000000000000000..25f524ba87945024350ed277757e8856f1eb6de6
--- /dev/null
+++ b/algo/qa/hitfind/BmonHitfindQaParameters.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   BmonHitfindQaParameters.h
+/// \brief  A BMON hitfinder QA parameter configuration
+/// \since  10.02.2025
+/// \author Sergei Zharko <s.zharko@gsi.de>
+
+#pragma once
+
+#include "bmon/CalibrateSetup.h"
+#include "bmon/HitfindSetup.h"
+
+#include <vector>
+
+namespace cbm::algo::bmon
+{
+  /// \struct HitfindQaParameters
+  /// \brief  A structure to handle BMON QA parameters
+  struct HitfindQaParameters {
+    /// \struct Diamond
+    /// \brief  A diamond representation
+    struct Diamond {
+      double timeRes{0.};      ///< Time resolution [ns]
+      double maxTimeDist{0.};  ///< Max time distance between digis in a hit [ns]
+      int32_t address{0};      ///< Address of a diamond
+      int32_t nChannels{0};    ///< Number of channels in a diamond
+      uint32_t deadStrips{0};  ///< A bit mask of dead strips
+    };
+
+    uint32_t selectionMask{0};  ///< A bitmask to distinguish different diamonds
+    std::vector<Diamond> diamonds{};
+
+    /// \brief Default constructor
+    HitfindQaParameters() = default;
+
+    /// \brief Constructor
+    /// \param calSetup  Calibration parameters
+    /// \param hitSetup  Hitfinder parameters
+    HitfindQaParameters(const CalibrateSetup& calSetup, const HitfindSetup& hitSetup);
+
+    /// \brief Returns an index of the diamond by the address
+    /// \param address  A hardware address of the digi
+    size_t GetDiamondIndex(uint32_t address) const { return ((selectionMask & address) >> fSelectionBitsOffset); }
+
+   private:
+    uint32_t fSelectionBitsOffset{0};  ///< Number of bits to the right from the first bit in the selection mask
+  };
+}  // namespace cbm::algo::bmon