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.

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::DmaCount

Public Functions

Dma(uint8_t id, uint8_t dmaInterruptId, uint8_t index, int mem, uint32_t registerBase, const char *dmaDevice, const char *uioDevice, uint32_t descriptorOffset, uint32_t descriptorPerDma, uint32_t packageSize, uint32_t dmaRamStartAddress)

Only constructor for the DMA class.

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

  • dmaInterruptId – The DMA interrupt ID.

  • index – The index of the DMA device.

  • mem – The memory identifier.

  • registerBase – The address of the DMA device register.

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

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

  • descriptorOffset – The offset of the DMA descriptor memory.

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

  • packageSize – The size of a package in DEFAULT_DATA_SIZE byte words.

  • dmaRamStartAddress – The start address of the DMA RAM (e.g. DMA_RAW_START_ADDRESS).

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 setFifoFullHandled()

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 fifoFullHandled() 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 getID() const

Get the ID of the DMA.

inline uint8_t getIndex() const

Get the index of the DMA.

inline uint32_t getDmaDescriptorCount() const

Get the amount of descriptors for the DMA.

void reset()

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

void enableInterrupt()

Enables the DMA interrupts as well as the UIO interrupts.

InterruptStatus waitForData()

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.

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 setStartDescriptorAddress(uint32_t address)

Sets the start descriptor address.

void setTailDescriptorAddress(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 getDataLength()

Gets the length of the data.

Usually it should be the same as DEFAULT_RAW_PACKAGE_SIZE_BYTES. When the measurement was stopped the last package might (most probably) be smaller.

Returns:

The length of the data as a uint32_t.

uint32_t getStatus()

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 hasStatusError()

Checks if there is a status error.

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

Returns:

true if there is a status error, false otherwise.

bool hasStatusError(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 hasError() const

Checks if there is an error in the DMA component.

Returns:

true if there is an error, false otherwise.

bool isRunning() const

Checks if the DMA is currently running.

Returns:

true if the DMA is running, false otherwise.

bool isStopped() const

Checks if the DMA is stopped.

Returns:

true if the DMA is stopped, false otherwise.

uint64_t *memoryMap() const

Returns a pointer to the memory map.

This function returns a pointer to the memory map used by the DMA component. The memory map is a uint64_t pointer that represents the starting address of the memory map.

Returns:

A pointer to the memory map.

uint32_t writeSize()

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 decreaseReadDifference()

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 currentReadDescriptor()

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 packageSize() const

Returns the package size.

virtual bool isCountDma() const

Returns false if the DMA is not a count DMA.

Returns:

true if the DMA is a count DMA, false otherwise.

Private Functions

void registerEnable()

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

void registerDisable()

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

Private Members

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 *DMA_DEVICE

The name of he DMA device to handle the memory.

const char *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 PACKAGE_SIZE

The size of a package in DEFAULT_DATA_SIZE byte words.

const uint32_t PACKAGE_SIZE_BYTES

The size of a package in bytes.

uint32_t mCurrentDescriptor = 0

The current write descriptor.

uint32_t mCurrentReadDescriptor = 0

The current read descriptor.

std::atomic<uint32_t> mReadDifference = {0}

The difference between the current read and write descriptor. RAM full depends on this value.

std::atomic<uint32_t> mReceivedDataPackets = {0}

The number of received data packets.

memorycontrol::MemoryMap mRegisterMap

The memory map used to access the DMA registers.

memorycontrol::MemoryMap mMemoryMap

The memory map used to access the DMA memory.

memorycontrol::Uio mUio

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

dma::DescriptorControl mDescriptorControl

The descriptor control object used to control the DMA descriptors.

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

Indicates whether the DMA is enabled.

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

Indicates whether the DMA is running.

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

Indicates whether the DMA is finished its operation.

std::chrono::time_point<std::chrono::steady_clock> mStopTime = {}

The time when the DMA was stopped.

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

The thread used to handle the DMA operations. It contains a loop which runs until the DMA is stopped.

std::atomic<bool> mExit = false

Indicates whether the DMA thread should exit.

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

Indicates whether the FIFO is full.

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

Indicates whether the FIFO full interrupt was handled. It is used for communication with the controller object.

bool mHasError = false

Indicates whether there is an error.

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 id, uint32_t registerBase, int mem, uint32_t descriptorOffset, uint32_t descriptorPerDma, uint32_t packageSizeBytes, uint32_t dmaRamStartAddress)

Constructor for DescriptorControl.

Parameters:
  • id – DMA ID.

  • registerBase – Register base address.

  • mem – Memory size.

  • descriptorOffset – Descriptor offset.

  • descriptorPerDma – Number of descriptors per DMA.

  • packageSizeBytes – Package size in bytes.

  • dmaRamStartAddress – Start address of the DMA RAM (e.g. DMA_RAW_START_ADDRESS).

~DescriptorControl() = default

Destructor for DescriptorControl.

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

Checks if there is an error.

Returns:

True if there is an error, false otherwise.

uint32_t getReceivedDataWordLength(uint32_t descriptorNumber)

Gets the number of received 32 bit words (yes not 64 bit).

The number of received 32 bit words is the number of bytes received divided by 4.

Parameters:

descriptorNumber – Descriptor number.

Returns:

The received data.

void writeDescriptors()

Writes the descriptors.

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

Private Functions

DescriptorControl(DescriptorControl&&) = delete
DescriptorControl &operator=(DescriptorControl&&) = delete

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 mMemoryMap

The memory map of the descriptor control registers.

Bibliography