Dma

The Dma component handles the configuration and control of the Direct Memory Access (DMA). It is used to transfer data from the hardware design to the memory. It can be used for data streams with 16 bit or 64 bit data width.

Additional information

The Dma component works only with the Dma implementation of AMD/Xilinx [1].

When creating a Dma object the corresponding DMA is configured using a memory map to access the DMA registers and a descriptor control to access the descriptor control registers. A Uio device is used to wait for Dma interrupts. On each interrupt it is checked if the interrupt was caused by the measurement stop. If this happened the DMA waits for the last transfer to finish and then the DMA is stopped.

Classes

DMA Class

class Dma

DMA class to handle the AXI DMA device.

This class is used to control the DMA device.

Objects of this class are supposed to run in a separate thread. Also another thread is created to handle the interrupts.

Subclassed by nexmess::components::dma::Dma16, nexmess::components::dma::Dma64

Public Functions

Dma(uint8_t dma_id, uint8_t dma_interrupt_id, uint8_t index, int mem, uint32_t register_base, const char *dma_device, const char *uio_device, uint32_t descriptor_offset, uint32_t descriptor_per_dma, uint32_t data_word_size, uint32_t package_size, uint32_t dma_ram_start_address, DmaPurpose purpose_of_use)

Only constructor for the DMA class.

Parameters:
  • dma_id – The DMA ID. The ID should be the index of the corresponding DMA device within the DMAS array.

  • dma_interrupt_id – The DMA interrupt ID.

  • index – The index of the DMA device.

  • mem – The memory identifier.

  • register_base – The address of the DMA device register.

  • dma_device – The name of the DMA device to handle the memory.

  • uio_device – The name of the UIO device to handle the interrupts.

  • descriptor_offset – The offset of the DMA descriptor memory.

  • descriptor_per_dma – The amount of DMA descriptors per DMA device.

  • data_word_size – Size of data word in bytes.

  • package_size – The size of a package in data_word_size byte words.

  • dma_ram_start_address – The start address of the DMA RAM (e.g. kDmaRawStartAddress).

  • purpose_of_use – The purpose of use of the DMA.

virtual ~Dma()

Destructor for the DMA class.

This destructor makes sure the DMA is disabled and the thread is joined.

Dma() = delete
Dma(const Dma&) = delete
Dma(Dma &&other) = delete
Dma &operator=(const Dma&) = delete
Dma &operator=(Dma&&) = delete
bool empty()

Checks if the DMA is empty.

Returns:

true if the DMA is empty, false otherwise.

bool full()

Checks if the DMA is full.

It is also true if the RAM is full.

Returns:

true if the DMA is full, false otherwise.

void set_fifo_full_handled()

Sets the flag indicating that the FIFO is full and has been handled.

This is set by the controller once the FIFO full interrupt has been handled.

bool fifo_full_handled() const

Checks if the FIFO full interrupt has been handled.

Returns:

true if the FIFO full interrupt has been handled, false otherwise.

inline uint8_t get_id() const

Get the ID of the DMA.

inline uint8_t get_index() const

Get the index of the DMA.

inline uint8_t get_dma_interrupt_id() const

Get the interrupt ID of the DMA.

inline uint32_t get_dma_descriptor_count() const

Get the amount of descriptors for the DMA.

void reset()

Sets the bit in the DMA control register to reset the DMA.

void enable_interrupt()

Enables the DMA interrupts as well as the UIO interrupts.

InterruptStatus wait_for_data()

Waits for interrupts and checks for available data.

This function handles the interrupts and re-enables them. It updates the descriptor pointers. It also checks if there is data available and sets the FIFO full flag if the FIFO is full. When the measurement is finished it handles it as well.

Returns:

The interrupt status.

virtual void run_dma_operations() = 0

Runs the DMA operations in the dedicated thread.

This method contains the main DMA loop logic and must be implemented by derived classes for type-specific handling.

void enable()

Enables the DMA operation.

It spawns the thread to handle the DMA operations.

void disable()

Disables the DMA operation.

It stops the thread to handle the DMA operations ans disables the DMA in hardware.

void set_start_descriptor_address(uint32_t address)

Sets the start descriptor address.

void set_tail_descriptor_address(uint32_t address)

Sets the tail descriptor address.

Writing to this register starts the actual DMA operation in hardware. From this point on the DMA will read the descriptors and write the data to the RAM when data is available.

uint32_t get_status()

Get the status of the DMA.

The status is read from the status register of the DMA.

Returns:

The status of the DMA as a 32-bit unsigned integer.

bool has_status_error()

Checks if there is a status error.

Is the same as has_status_error(uint32_t status) but reads the status register first.

Returns:

true if there is a status error, false otherwise.

bool has_status_error(uint32_t status)

Checks if there is a status error.

Parameters:

status – The value if the status register.

Returns:

true if there is a status error, false otherwise.

bool has_error() const

Checks if there is an error in the DMA component.

Returns:

true if there is an error, false otherwise.

bool is_running() const

Checks if the DMA is currently running.

Returns:

true if the DMA is running, false otherwise.

bool is_stopped() const

Checks if the DMA is stopped.

Returns:

true if the DMA is stopped, false otherwise.

uint8_t *memory_map_bytes() const

Returns a pointer to the memory map as bytes.

This function returns a generic byte pointer to the memory map used by the DMA component. Derived classes should provide typed accessors for their specific data width.

Returns:

A byte pointer to the memory map.

virtual uint32_t write_size() = 0

Returns the size of data which is received and can be handled.

The returned write size is never bigger than one portion of memory described by one DMA descriptor. This makes sure that we don’t read data after the last descriptor (wrap around).

This function reduces the amount of available data for the next call.

This function must be called for continuous operation.

Returns:

The size of the write operation in bytes.

void decrease_read_difference()

Decreases the read difference.

This function is responsible for decreasing the read difference. It should be called after the received data of one descriptor has been handled.

This function must be called for continuous operation.

uint32_t current_read_descriptor()

Returns the current read descriptor.

This function returns the current read descriptor used by the DMA module. This also updated the read descriptor pointer to read the next descriptor the next time.

This function must be called for continuous operation.

Returns:

The current read descriptor.

uint32_t data_word_size() const

Returns the data word size.

uint32_t package_size() const

Returns the package size.

DmaPurpose get_purpose_of_use() const

Get the purpose of use of the DMA.

bool compare_purpose_of_use(DmaPurpose purpose) const

Returns the comparison value for a purpose of use of the DMA.

Parameters:

purpose – The purpose to compare against.

Returns:

true if the purpose of use of the DMA is equal to the input purpose , false otherwise.

Protected Functions

void register_enable()

Sets the DMAs register so that it is ready to receive data.

void register_disable()

Sets the DMAs register so that it is not ready to receive data.

Protected Attributes

const uint8_t ID_

The DMA ID.

The ID is supposed to be the index of the corresponding DMA device within the DMAS array.

const uint8_t DMA_INTERRUPT_ID_

The DMA interrupt ID.

const uint8_t INDEX_

The index of the DMA device.

const uint32_t REGISTER_BASE_

The address of the DMA device register.

const char *const DMA_DEVICE_

The name of he DMA device to handle the memory.

const char *const UIO_DEVICE_

The name of the UIO device to handle the DMA interrupts.

const uint32_t DESCRIPTOR_OFFSET_

The offset of the DMA descriptor memory.

const uint32_t DESCRIPTOR_PER_DMA_

The amount of DMA descriptors per DMA device.

const uint32_t DATA_WORD_SIZE_

The size of a data word in bytes.

const uint32_t PACKAGE_SIZE_

The size of a package in kDefaultDataSize byte words.

const uint32_t PACKAGE_SIZE_BYTES_

The size of a package in bytes.

const DmaPurpose PURPOSE_OF_USE_

Purpose of use of the DMA.

uint32_t current_descriptor_ = 0

The current write descriptor.

uint32_t current_read_descriptor_ = 0

The current read descriptor.

std::atomic<uint32_t> read_difference_{0}

The difference between the current read and write descriptor.

RAM full depends on this value.

std::atomic<uint32_t> received_data_packets_{0}

The number of received data packets.

memorycontrol::MemoryMap register_map_

The memory map used to access the DMA registers.

memorycontrol::MemoryMap memory_map_

The memory map used to access the DMA memory.

memorycontrol::Uio uio_

The UIO object used to handle the DMA/FIFO and stopped interrupts.

dma::DescriptorControl descriptor_control_

The descriptor control object used to control the DMA descriptors.

std::atomic<bool> enabled_ = {false}

Indicates whether the DMA is enabled.

std::atomic<bool> running_ = {false}

Indicates whether the DMA is running.

std::atomic<bool> stopped_{false}

Indicates whether the DMA is finished its operation.

std::chrono::time_point<std::chrono::steady_clock> stop_time_

The time when the DMA was stopped.

std::unique_ptr<std::thread> thread_ = nullptr

The thread used to handle the DMA operations.

It contains a loop which runs until the DMA is stopped.

std::atomic<bool> exit_ = false

Indicates whether the DMA thread should exit.

std::atomic<bool> fifo_full_ = {false}

Indicates whether the FIFO is full.

std::atomic<bool> fifo_full_handled_{false}

Indicates whether the FIFO full interrupt was handled.

It is used for communication with the controller object.

bool has_error_ = false

Indicates whether there is an error.

16-bit DMA Class

class Dma16 : public nexmess::components::dma::Dma

DMA class for handling 16-bit data streams.

This class extends the base Dma class to handle 16-bit data transfers. It overrides specific methods to handle 16-bit word calculations. Note: The hardware still uses 64-bit transfers, but the data is packed with 4 x 16-bit values per 64-bit word.

Public Functions

Dma16(uint8_t dma_id, uint8_t dma_interrupt_id, uint8_t index, int mem, uint32_t register_base, const char *dma_device, const char *uio_device, uint32_t descriptor_offset, uint32_t descriptor_per_dma, uint32_t data_word_size, uint32_t package_size, uint32_t dma_ram_start_address, DmaPurpose purpose_of_use)

Constructor for the Dma16 class.

Parameters:
  • dma_id – The DMA ID.

  • dma_interrupt_id – The DMA interrupt ID.

  • index – The index of the DMA device.

  • mem – The memory identifier.

  • register_base – The address of the DMA device register.

  • dma_device – The name of the DMA device to handle the memory.

  • uio_device – The name of the UIO device to handle the interrupts.

  • descriptor_offset – The offset of the DMA descriptor memory.

  • descriptor_per_dma – The amount of DMA descriptors per DMA device.

  • data_word_size – Size of 16-bit data word in bytes (2 bytes).

  • package_size – The size of a package in 16-bit words.

  • dma_ram_start_address – The start address of the DMA RAM.

  • purpose_of_use – The purpose of use of the DMA.

~Dma16() override = default

Destructor for the Dma16 class.

Dma16(const Dma16&) = delete
Dma16(Dma16&&) = delete
Dma16 &operator=(const Dma16&) = delete
Dma16 &operator=(Dma16&&) = delete
virtual uint32_t write_size() override

Returns the size of data which is received and can be handled.

Calculates the write size for 16-bit data streams.

Returns:

The size of the write operation in bytes.

virtual void run_dma_operations() override

Runs the DMA operations for 16-bit data streams.

Implements the main DMA thread loop with 16-bit specific logic.

Private Functions

uint32_t get_data_length()

Gets the length of the data in 16-bit words.

Converts the byte length from the descriptor to 16-bit word count.

Returns:

The length of the data in 16-bit words.

uint16_t *memory_map() const

Returns a typed pointer to the memory map for 16-bit access.

Returns:

A uint16_t pointer to the memory map.

bool initialize_dma_hardware()

Initializes DMA hardware and checks for errors.

Returns:

true if initialization succeeded, false on error.

bool check_finish_pattern(uint32_t previous_descriptor, uint32_t data_length)

Checks if a finish pattern is detected in the data.

Parameters:
  • previous_descriptor – The descriptor to check.

  • data_length – The length of data in the descriptor.

Returns:

true if finish pattern detected, false otherwise.

64-bit DMA Class

class Dma64 : public nexmess::components::dma::Dma

DMA class for handling 64-bit data streams.

This class extends the base Dma class to handle 64-bit data transfers. It overrides specific methods to handle 64-bit word calculations.

Public Functions

Dma64(uint8_t dma_id, uint8_t dma_interrupt_id, uint8_t index, int mem, uint32_t register_base, const char *dma_device, const char *uio_device, uint32_t descriptor_offset, uint32_t descriptor_per_dma, uint32_t data_word_size, uint32_t package_size, uint32_t dma_ram_start_address, DmaPurpose purpose_of_use)

Constructor for the Dma64 class.

Parameters:
  • dma_id – The DMA ID.

  • dma_interrupt_id – The DMA interrupt ID.

  • index – The index of the DMA device.

  • mem – The memory identifier.

  • register_base – The address of the DMA device register.

  • dma_device – The name of the DMA device to handle the memory.

  • uio_device – The name of the UIO device to handle the interrupts.

  • descriptor_offset – The offset of the DMA descriptor memory.

  • descriptor_per_dma – The amount of DMA descriptors per DMA device.

  • data_word_size – Size of data word in bytes (should be 8 for 64-bit).

  • package_size – The size of a package in data_word_size byte words.

  • dma_ram_start_address – The start address of the DMA RAM.

  • purpose_of_use – The purpose of use of the DMA.

~Dma64() override = default

Destructor for the Dma64 class.

Dma64(const Dma64&) = delete
Dma64(Dma64&&) = delete
Dma64 &operator=(const Dma64&) = delete
Dma64 &operator=(Dma64&&) = delete
virtual uint32_t write_size() override

Returns the size of data which is received and can be handled.

Calculates the write size for 64-bit data streams.

Returns:

The size of the write operation in bytes.

virtual void run_dma_operations() override

Runs the DMA operations for 64-bit data streams.

Implements the main DMA thread loop with 64-bit specific logic.

Private Functions

uint32_t get_data_length()

Gets the length of the data in 64-bit words.

Converts the byte length from the descriptor to 64-bit word count.

Returns:

The length of the data in 64-bit words.

uint64_t *memory_map() const

Returns a typed pointer to the memory map for 64-bit access.

Returns:

A uint64_t pointer to the memory map.

bool initialize_dma_hardware()

Initializes DMA hardware and checks for errors.

Returns:

true if initialization succeeded, false on error.

bool check_finish_pattern(uint32_t previous_descriptor, uint32_t data_length)

Checks if a finish pattern is detected in the data.

Parameters:
  • previous_descriptor – The descriptor to check.

  • data_length – The length of data in the descriptor.

Returns:

true if finish pattern detected, false otherwise.

DescriptorControl Class

class DescriptorControl

Controls the descriptors for DMA operations.

The DescriptorControl class provides functionality to control the descriptors used for DMA operations. It manages the DMA ID, register base address, and memory size. It also provides methods to check for errors, retrieve the number of received data words, and write descriptors.

Public Functions

DescriptorControl(uint32_t dma_id, uint32_t register_base, int mem, uint32_t descriptor_offset, uint32_t descriptor_per_dma, uint32_t package_size_bytes, uint32_t dma_ram_start_address)

Constructor for DescriptorControl.

Parameters:
  • dma_id – DMA ID.

  • register_base – Register base address.

  • mem – Memory size.

  • descriptor_offset – Descriptor offset.

  • descriptor_per_dma – Number of descriptors per DMA.

  • package_size_bytes – Package size in bytes.

  • dma_ram_start_address – Start address of the DMA RAM (e.g. kDmaRawStartAddress).

~DescriptorControl() = default

Destructor for DescriptorControl.

DescriptorControl() = delete
DescriptorControl(const DescriptorControl&) = delete
void operator=(const DescriptorControl&) = delete
DescriptorControl(DescriptorControl&&) = delete
DescriptorControl &operator=(DescriptorControl&&) = delete
bool has_error() const

Checks if there is an error.

Returns:

True if there is an error, false otherwise.

uint32_t get_received_data_byte_length(uint32_t descriptor_number)

Gets the number of received bytes.

Returns the number of bytes received as stored in the descriptor status.

Parameters:

descriptor_number – Descriptor number.

Returns:

The received data length in bytes.

void write_descriptors()

Writes the descriptors.

The DMA is set into circular mode, so the last descriptor points to the first one.

Private Members

const uint32_t DMA_ID_

The DMA ID.

const uint32_t REGISTER_BASE_

The register base address.

const uint32_t REGISTER_SIZE_

The register size.

const uint32_t DESCRIPTOR_OFFSET_

The offset of the first descriptor from the base.

const uint32_t DESCRIPTOR_PER_DMA_

The number of descriptors per DMA.

const uint32_t PACKAGE_SIZE_BYTES_

The package size in bytes.

const uint32_t DMA_RAM_START_ADDRESS_

The start address of the DMA RAM.

memorycontrol::MemoryMap memory_map_

The memory map of the descriptor control registers.

Bibliography