Loading...
Searching...
No Matches
libm2k

# License

libm2k is licensed under the GNU Lesser General Public License v2.1

# Architecture

libm2k is a C++ library for interfacing with the ADALM2000, splitted into more correlated components, interconnected by a context. These M2K components represent the functionalities of ADALM2000:

- AnalogIn - oscilloscope or voltmeter
- AnalogOut - signal generator
- Digital - logic analyzer or pattern generator
- PowerSupply - constant voltage generator
- DMM - digital multimeter

## Class Diagram

The class diagram containing details for all public classes of libm2k.

## Top Level Diagram

The top level diagram provides an overview for the library structure. The components are organized in their corresponding namespaces.

## M2K Open Sequence Diagram

In this diagram the necessary steps to create an M2K context and get a specific device are presented.

## Asynchronous Acquisition Sequence Diagram

The sequence diagram shows an example to the asynchronous acquisition flow for Analog In or Digital In. Running "startAcquisition(number_of_samples)" will create, initialize and populate the available kernel buffers with data. Everytime we call "getSamples", we retrieve data from those kernel buffers, which will automatically be refilled.

## Synchronous Acquisition Sequence Diagram

The sequence diagram shows an example to the synchronous acquisition flow for Analog In or Digital In. Running "getSamples(number_of_samples)" will create and initialize, but it will also populate all the available kernel buffers with data and it will return one buffer to the user.

# Python Bindings

In order to use libm2k in Python applications please check the libm2k Python Bindings API

# Example

The following code shows a simple example on how to use libm2k together with the digital side of ADALM2000.

There are multiple examples provided for libm2k and can be found on the Github libm2k examples page. The examples are created to ease the work for a libm2k user. To get familiar with libm2k API, the examples can be modified and built out of the libm2k source code tree by keeping the CMake configuration file provided for each example.

// This example will generate a binary counter on the first N_BITS of the
// digital interface and read them back - no additional connection required
#include <iostream>
#include <libm2k/m2k.hpp>
#include <libm2k/context.hpp>
#include <libm2k/contextbuilder.hpp>
#include <libm2k/digital/m2kdigital.hpp>
#include <bitset>
using namespace std;
using namespace libm2k;
using namespace libm2k::digital;
using namespace libm2k::context;
#define N_BITS (4)
int main()
{
Context *c = contextOpen();
if (!c) {
std::cout << "Connection Error: No ADALM2000 device available/connected to your PC." << std::endl;
return 1;
}
M2k* ctx = c->toM2k();
M2kDigital *dig = ctx->getDigital();
dig->setSampleRateIn(100000);
dig->setSampleRateOut(100000);
for(int i=0;i<N_BITS;i++)
{
dig->setDirection(i, DIO_OUTPUT);
dig->enableChannel(i, true);
}
vector<unsigned short> bufferOut;
vector<unsigned short> bufferIn;
for(int i=0;i< (1<<N_BITS); i++)
{
bufferOut.push_back(i);
}
dig->setCyclic(true);
dig->push(bufferOut);
bufferIn = dig->getSamples(1000);
for(auto val : bufferIn)
{
cout<<bitset<16>(val)<<endl;
}
dig->stopBufferOut();
contextClose(ctx);
return 0;
}
libm2k::context::Context
Controls the IIO context.
Definition context.hpp:52
libm2k::context::M2k
Controls the ADALM2000.
Definition m2k.hpp:55
libm2k::digital::M2kDigital
Controls the digital input and output segment.
Definition m2kdigital.hpp:45
libm2k::context::Context::toM2k
virtual M2k * toM2k()=0
Convert the current context to M2k context, if possible.
libm2k::context::contextClose
LIBM2K_API void contextClose(Context *ctx, bool deinit=true)
Destroy the given context.
libm2k::digital::M2kDigital::enableChannel
virtual void enableChannel(unsigned int index, bool enable)=0
Enable or disable the given digital channel.
libm2k::digital::M2kDigital::push
virtual void push(std::vector< unsigned short > const &data)=0
Send the samples to all digital channels.
libm2k::digital::M2kDigital::getSamples
virtual std::vector< unsigned short > getSamples(unsigned int nb_samples)=0
Retrieve a specific number of samples.
libm2k::digital::M2kDigital::setCyclic
virtual void setCyclic(bool cyclic)=0
Enable or disable the cyclic mode for all digital channels.
libm2k::digital::M2kDigital::setDirection
virtual void setDirection(unsigned short mask)=0
Set the direction for all digital channels.
libm2k::digital::M2kDigital::setSampleRateIn
virtual double setSampleRateIn(double samplerate)=0
Set the sample rate for all digital input channels.
libm2k::digital::M2kDigital::stopBufferOut
virtual void stopBufferOut()=0
Stop all digital channels from sending the signals.
libm2k::digital::M2kDigital::setSampleRateOut
virtual double setSampleRateOut(double samplerate)=0
Set the sample rate for all digital output channels.
libm2k::context::M2k::getDigital
virtual libm2k::digital::M2kDigital * getDigital()=0
Retrieve the Digital object.

# FAQ

Useful questions and answers for the libm2k API usage and ADALM2000 manipulation

## How can I acquire raw data fast and convert it to the corresponding value in Volts (in Python)?

The Python bindings API are not a 100% mirror of the C++ code. Therefore, some methods might have a slightly different return type for Python (it is necessary to check the Python Bindings API Documentation listed above). For example, the getSamplesRawInterleaved() method will return 4*nb_samples elements in the Python list. In order to make the acquisition faster, all the samples are returned in a bytes list. One sample for one channel (for AnalogIn) is represented using 2 bytes. The returned list of bytes will be interleaved, this meaning that it should be interpreted as one sample from CHANNEL_1, one sample from CHANNEL_2 and so on. One thing to keep in mind is that a sample corresponds to 2 elements in the list.

Let's take an example:

samples = getSamplesRawInterleaved(10)
samples.tolist()
#will return:
[243, 255, 2, 0, 246, 255, 2, 0, 244, 255, 2, 0, 246, 255, 2, 0, 244, 255, 2, 0, 244, 255, 1, 0, 243, 255, 0, 0, 245, 255, 3, 0, 245, 255, 2, 0, 245, 255, 2, 0]
samples.tobytes()
#will return:
b'\xf3\xff\x02\x00\xf6\xff\x02\x00\xf4\xff\x02\x00\xf6\xff\x02\x00\xf4\xff\x02\x00\xf4\xff\x01\x00\xf3\xff\x00\x00\xf5\xff\x03\x00\xf5\xff\x02\x00\xf5\xff\x02\x00'
#[243, 255] corresponds to the first sample on CHANNEL_1
#[2, 0] corresponds to the first sample on CHANNEL_2

In order to convert all the samples you can use the following chunk of Python code:

import struct
#enable channels, acquire samples
samples = samples.tobytes()
count = int(len(samples)/2)
value_list = struct.unpack('h'*count, samples) #'h' is the format for short
#value_list will be similar to the following: (-13, 2, -10, 2, -12, 2, -10, 2, -12, 2, -12, 1, -13, 0, -11, 3, -11, 2, -11, 2)

Next thing is to convert it into Volts. In Python, for AnalogIn() you have 2 exposed methods: libm2k::analog::M2kAnalogIn::convertVoltsToRaw(unsigned int channel, double voltage) and libm2k::analog::M2kAnalogIn::convertRawToVolts(unsigned int channel, short raw). Running convertRawToVolts(0, value_list[0]) should provide the needed Volts value for CHANNEL_1.