Skip to content

Commit

Permalink
M2kAnalogOut: ensure DAC starts at 0V after a stop
Browse files Browse the repository at this point in the history
- This update ensures the `raw_enable` attribute is automatically set
to `enabled` when the M2kAnalogOut class is instantiated and after a reset.
- With raw_enable active, the output reflects the value set in the `raw` attribute.
- During buffer operations involving DMA, the firmware temporarily disables
`raw_enable` to allow proper DMA output. Once the DMA transaction completes,
`raw_enable` is restored to its initial state, ensuring consistent behavior.
- The change introduced in this commit sets `raw` to 0 and ensures `raw_enable`
is set. This guarantees that, upon restart, the output begins at 0V, avoiding
the use of old raw values or residual samples from the last sample hold state.

Signed-off-by: Adrian Stanea <[email protected]>
  • Loading branch information
Adrian-Stanea committed Aug 28, 2024
1 parent dc8220e commit 336b683
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 18 deletions.
6 changes: 6 additions & 0 deletions include/libm2k/analog/m2kanalogout.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,9 @@ class LIBM2K_API M2kAnalogOut
* @brief Sets the voltage output of the DAC channel
* @param chn_idx - unsigned int representing the index of the channel
* @param volts - actual value to be set
*
* @note In scenarios where the DMA is not active, such as when an output buffer is destroyed,
* the DAC will revert to using the raw value set by this function.
* @return unsigned short - the corresponding raw value for the given voltage
*/
virtual unsigned short setVoltage(unsigned int chn_idx, double volts) = 0;
Expand All @@ -484,6 +487,9 @@ class LIBM2K_API M2kAnalogOut
* @brief Sets the raw output of the DAC channel
* @param chn_idx - unsigned int representing the index of the channel
* @param raw - actual value to be set
*
* @note In scenarios where the DMA is not active, such as when an output buffer is destroyed,
* the DAC will revert to using the raw value set by this function.
* @return unsigned short - the value set in the raw attribute
*/
virtual unsigned short setVoltageRaw(unsigned int chn_idx, unsigned short raw) = 0;
Expand Down
95 changes: 77 additions & 18 deletions src/analog/m2kanalogout_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ M2kAnalogOutImpl::M2kAnalogOutImpl(iio_context *ctx, std::vector<std::string> da
m_trigger(trigger)
{
LIBM2K_LOG(INFO, "[BEGIN] Initialize M2kAnalogOut");
firmware_version = Utils::getFirmwareVersion(ctx);
m_dac_devices.push_back(new DeviceOut(ctx, dac_devs.at(0)));
m_dac_devices.push_back(new DeviceOut(ctx, dac_devs.at(1)));

Expand Down Expand Up @@ -78,10 +79,17 @@ M2kAnalogOutImpl::M2kAnalogOutImpl(iio_context *ctx, std::vector<std::string> da
// auto_rearm_trigger attribute is only available in firmware versions newer than 0.33
m_auto_rearm_trigger_available = getDacDevice(0)->hasGlobalAttribute("auto_rearm_trigger");

// raw and raw_enable attributes are only available in firmware versions newer than 0.32
m_raw_enable_available.push_back(getDacDevice(0)->getChannel(0, true)->hasAttribute("raw_enable"));
m_raw_enable_available.push_back(getDacDevice(1)->getChannel(0, true)->hasAttribute("raw_enable"));
m_raw_available.push_back(getDacDevice(0)->getChannel(0, true)->hasAttribute("raw"));
m_raw_available.push_back(getDacDevice(1)->getChannel(0, true)->hasAttribute("raw"));

if (m_raw_enable_available.at(0) && m_raw_enable_available.at(1)) {
getDacDevice(0)->getChannel(0, true)->setStringValue("raw_enable", "enabled");
getDacDevice(1)->getChannel(0, true)->setStringValue("raw_enable", "enabled");
}

LIBM2K_LOG(INFO, "[END] Initialize M2kAnalogOut");
}

Expand Down Expand Up @@ -144,33 +152,75 @@ void M2kAnalogOutImpl::loadNbKernelBuffers()

unsigned short M2kAnalogOutImpl::setVoltage(unsigned int chn_idx, double volts)
{
auto chn = getDacDevice(chn_idx)->getChannel(0, true);
auto raw = static_cast<long long>(convertVoltsToRaw(chn_idx, volts));
long long ret = 0;
// having the raw_enable attribute set to enable should give at the dac output the corresponding raw value
if (m_raw_available.at(chn_idx) && m_raw_enable_available.at(chn_idx)) {
chn->setStringValue("raw_enable", "enabled");
chn->setLongValue("raw", raw);
ret = chn->getLongValue("raw");
} else {
setRawEnable(chn_idx, true);
setRaw(chn_idx, raw);
return getRaw(chn_idx);
}

unsigned short M2kAnalogOutImpl::setVoltageRaw(unsigned int chn_idx, unsigned short raw)
{
setRawEnable(chn_idx, true);
setRaw(chn_idx, raw);
return getRaw(chn_idx);
}

/**
* @note The `raw_enable` flag must be enabled for this value to take effect.
* @note The `raw` value is used when DMA output is invalid, such as when the DMA buffer is destroyed, ensuring predictable output.
*/
void M2kAnalogOutImpl::setRaw(unsigned int chn_idx, unsigned short raw)
{
if (!m_raw_available.at(chn_idx)) {
THROW_M2K_EXCEPTION("Invalid firmware version: 0.32 or greater is required.", libm2k::EXC_INVALID_FIRMWARE_VERSION);
}
return ret;
if (chn_idx >= m_dac_devices.size()) {
THROW_M2K_EXCEPTION("Analog Out: No such channel", libm2k::EXC_OUT_OF_RANGE);
}
auto chn = getDacDevice(chn_idx)->getChannel(0, true);
chn->setLongValue("raw", static_cast<long long>(raw));
}

unsigned short M2kAnalogOutImpl::setVoltageRaw(unsigned int chn_idx, unsigned short raw)
unsigned short M2kAnalogOutImpl::getRaw(unsigned int chn_idx) const
{
if (!m_raw_available.at(chn_idx)) {
THROW_M2K_EXCEPTION("Invalid firmware version: 0.32 or greater is required.", libm2k::EXC_INVALID_FIRMWARE_VERSION);
}
if (chn_idx >= m_dac_devices.size()) {
THROW_M2K_EXCEPTION("Analog Out: No such channel", libm2k::EXC_OUT_OF_RANGE);
}
auto chn = getDacDevice(chn_idx)->getChannel(0, true);
long long ret = 0;
// having the raw_enable attribute set to enable should give at the dac output the corresponding raw value
if (m_raw_available.at(chn_idx) && m_raw_enable_available.at(chn_idx)) {
chn->setStringValue("raw_enable", "enabled");
chn->setLongValue("raw", static_cast<long long>(raw));
ret = chn->getLongValue("raw");
} else {
return chn->getLongValue("raw");
}

/**
* @brief Enables DAC output to fall back to the raw value when DMA output is invalid.
*
* @note The `raw_enable` attribute is automatically enabled upon DAC reset, ensuring that
* the output is driven by the `raw` value if the DMA buffer is destroyed or unavailable.
*/
void M2kAnalogOutImpl::setRawEnable(unsigned int chn_idx, bool enable)
{
if (!m_raw_enable_available.at(chn_idx)) {
THROW_M2K_EXCEPTION("Invalid firmware version: 0.32 or greater is required.", libm2k::EXC_INVALID_FIRMWARE_VERSION);
}
return ret;
if (chn_idx >= m_dac_devices.size()) {
THROW_M2K_EXCEPTION("Analog Out: No such channel", libm2k::EXC_OUT_OF_RANGE);
}
auto chn = getDacDevice(chn_idx)->getChannel(0, true);
chn->setStringValue("raw_enable", enable ? "enabled" : "disabled");
}

bool M2kAnalogOutImpl::getRawEnable(unsigned int chn_idx) const
{
if (!m_raw_enable_available.at(chn_idx)) {
THROW_M2K_EXCEPTION("Invalid firmware version: 0.32 or greater is required.", libm2k::EXC_INVALID_FIRMWARE_VERSION);
}
if (chn_idx >= m_dac_devices.size()) {
THROW_M2K_EXCEPTION("Analog Out: No such channel", libm2k::EXC_OUT_OF_RANGE);
}
auto chn = getDacDevice(chn_idx)->getChannel(0, true);
return chn->getStringValue("raw_enable") == "enabled";
}

double M2kAnalogOutImpl::getCalibscale(unsigned int index)
Expand Down Expand Up @@ -616,13 +666,22 @@ void M2kAnalogOutImpl::stop()
for (DeviceOut* dev : m_dac_devices) {
dev->stop();
}

if (firmware_version >= "v0.32") {
for (unsigned int i = 0; i < m_dac_devices.size(); i++) {
setRawEnable(i, true);
setRaw(i, 0);
}
}
}

void M2kAnalogOutImpl::stop(unsigned int chn)
{
m_m2k_fabric->setBoolValue(chn, true, "powerdown", true);
setSyncedDma(true, chn);
getDacDevice(chn)->stop();
setRawEnable(chn, true);
setRaw(chn, 0);
}

void M2kAnalogOutImpl::enableChannel(unsigned int chnIdx, bool enable)
Expand Down
7 changes: 7 additions & 0 deletions src/analog/m2kanalogout_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ class M2kAnalogOutImpl : public M2kAnalogOut
bool getBufferRearmOnTrigger() override;

private:
std::string firmware_version;
std::shared_ptr<libm2k::utils::DeviceGeneric> m_m2k_fabric;
libm2k::M2kHardwareTrigger *m_trigger;
std::vector<double> m_max_samplerate;
Expand All @@ -120,6 +121,12 @@ class M2kAnalogOutImpl : public M2kAnalogOut
DeviceOut* getDacDevice(unsigned int chnIdx) const;
void syncDevice();
double convRawToVolts(short raw, double vlsb, double filterCompensation);

void setRaw(unsigned int chn_idx, unsigned short raw);
unsigned short getRaw(unsigned int chn_idx) const;
void setRawEnable(unsigned int chn_idx, bool enable);
bool getRawEnable(unsigned int chn_idx) const;

};
}
}
Expand Down

0 comments on commit 336b683

Please sign in to comment.