/**************************************************************************//**
* @file
* @author Steve Lascos
* @company Blackaddr Audio
*
* LibMemoryManagment is a class for providing access to external SPI based
* SRAM with the optional convience of breaking it up into 'slots' which are smaller
* memory entities.
* @details This class treats an external memory as a pool from which the user requests
* a block. When using that block, the user need not be concerned with where the pool
* it came from, they only deal with offsets from the start of their memory block. Ie.
* Your particular slot of memory appears to you to start at 0 and end at whatever size
* was requested.
*
* @copyright This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*****************************************************************************/
#ifndef __LIBMEMORYMANAGEMENT_H
#define __LIBMEMORYMANAGEMENT_H
#include
#include "BAHardware.h"
#include "BASpiMemory.h"
namespace BAGuitar {
/**************************************************************************//**
* MemConfig contains the configuration information associated with a particular
* SPI interface.
*****************************************************************************/
struct MemConfig {
size_t size; ///< the total size of the external SPI memory
size_t totalAvailable; ///< the number of bytes available (remaining)
size_t nextAvailable; ///< the starting point for the next available slot
BASpiMemory *m_spi = nullptr; ///< handle to the SPI interface
};
class ExternalSramManager; // forward declare so ExtMemSlot can declared friendship with it
/**************************************************************************//**
* ExtMemSlot provides a convenient interface to a particular slot of an
* external memory.
* @details the memory can be access randomly, as a single word, as a block of
* data, or as circular queue.
*****************************************************************************/
class ExtMemSlot {
public:
/// clear the entire contents of the slot by writing zeros
/// @returns true on success
bool clear();
/// set a new write position (in bytes) for circular operation
/// @param offsetBytes moves the write pointer to the specified offset from the slot start
/// @returns true on success, else false if offset is beyond slot boundaries.
bool setWritePosition(size_t offsetBytes);
/// returns the currently set write pointer pointer
/// @returns the write position value
size_t getWritePosition() const { return m_currentWrPosition-m_start; }
/// set a new read position (in bytes) for circular operation
/// @param offsetBytes moves the read pointer to the specified offset from the slot start
/// @returns true on success, else false if offset is beyond slot boundaries.
bool setReadPosition(size_t offsetBytes);
/// returns the currently set read pointer pointer
/// @returns the read position value
size_t getReadPosition() const { return m_currentRdPosition-m_start; }
/// Write a block of 16-bit data to the memory at the specified offset
/// @param offsetBytes offset in bytes from start of slot
/// @param dataPtr pointer to start of block of 16-bit data
/// @param numWords number of 16-bit words to transfer
/// @returns true on success, else false on error
bool write16(size_t offsetBytes, int16_t *dest, size_t numWords);
/// Write a block of zeros (16-bit) to the memory at the specified offset
/// @param offsetBytes offset in bytes from start of slot
/// @param numWords number of 16-bit words to transfer
/// @returns true on success, else false on error
bool zero16(size_t offsetBytes, size_t numWords);
/// Read a block of 16-bit data from the memory at the specified location
/// @param dest pointer to destination for the read data
/// @param offsetBytes offset in bytes from start of slot
/// @param numWords number of 16-bit words to transfer
/// @returns true on success, else false on error
bool read16(int16_t *dest, size_t offsetBytes, size_t numWords);
/// Read the next in memory during circular operation
/// @returns the next 16-bit data word in memory
uint16_t readAdvance16();
/// Read the next block of numWords during circular operation
/// @details, dest is ignored when using DMA
/// @param dest pointer to the destination of the read.
/// @param numWords number of 16-bit words to transfer
/// @returns true on success, else false on error
bool readAdvance16(int16_t *dest, size_t numWords);
/// Write a block of 16-bit data from the specified location in circular operation
/// @param src pointer to the start of the block of data to write to memory
/// @param numWords number of 16-bit words to transfer
/// @returns true on success, else false on error
bool writeAdvance16(int16_t *src, size_t numWords);
/// Write a single 16-bit data to the next location in circular operation
/// @param data the 16-bit word to transfer
/// @returns true on success, else false on error
bool writeAdvance16(int16_t data); // write just one data
/// Write a block of 16-bit data zeros in circular operation
/// @param numWords number of 16-bit words to transfer
/// @returns true on success, else false on error
bool zeroAdvance16(size_t numWords);
/// Get the size of the memory slot
/// @returns size of the slot in bytes
size_t size() const { return m_size; }
/// Ensures the underlying SPI interface is enabled
/// @returns true on success, false on error
bool enable() const;
/// Checks whether underlying SPI interface is enabled
/// @returns true if enabled, false if not enabled
bool isEnabled() const;
bool isUseDma() const { return m_useDma; }
bool isWriteBusy() const;
bool isReadBusy() const;
/// DEBUG USE: prints out the slot member variables
void printStatus(void) const;
private:
friend ExternalSramManager; ///< gives the manager access to the private variables
bool m_valid = false; ///< After a slot is successfully configured by the manager it becomes valid
size_t m_start = 0; ///< the external memory address in bytes where this slot starts
size_t m_end = 0; ///< the external memory address in bytes where this slot ends (inclusive)
size_t m_currentWrPosition = 0; ///< current write pointer for circular operation
size_t m_currentRdPosition = 0; ///< current read pointer for circular operation
size_t m_size = 0; ///< size of this slot in bytes
bool m_useDma = false; ///< when TRUE, BASpiMemoryDMA will be used.
SpiDeviceId m_spiId; ///< the SPI Device ID
BASpiMemory *m_spi = nullptr; ///< pointer to an instance of the BASpiMemory interface class
};
/**************************************************************************//**
* ExternalSramManager provides a class to handle dividing an external SPI RAM
* into independent slots for general use.
* @details the class does not support deallocated memory because this would cause
* fragmentation.
*****************************************************************************/
class ExternalSramManager final {
public:
ExternalSramManager() = delete;
/// The manager is constructed by specifying how many external memories to handle allocations for
/// @param numMemories the number of external memories
ExternalSramManager(unsigned numMemories = 1);
virtual ~ExternalSramManager();
/// Query the amount of available (unallocated) memory
/// @details note that currently, memory cannot be allocated.
/// @param mem specifies which memory to query, default is memory 0
/// @returns the available memory in bytes
size_t availableMemory(BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0);
/// Request memory be allocated for the provided slot
/// @param slot a pointer to the global slot object to which memory will be allocated
/// @param delayMilliseconds request the amount of memory based on required time for audio samples, rather than number of bytes.
/// @param mem specify which external memory to allocate from
/// @param dmaBufferSize When > 0, DMA mode is used with the specified DMA buffer size
/// @returns true on success, otherwise false on error
bool requestMemory(ExtMemSlot *slot, float delayMilliseconds, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0, bool useDma = false);
/// Request memory be allocated for the provided slot
/// @param slot a pointer to the global slot object to which memory will be allocated
/// @param sizeBytes request the amount of memory in bytes to request
/// @param mem specify which external memory to allocate from
/// @param dmaBufferSize When > 0, DMA mode is used with the specified DMA buffer size
/// @returns true on success, otherwise false on error
bool requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0, bool useDma = false);
private:
static bool m_configured; ///< there should only be one instance of ExternalSramManager in the whole project
static MemConfig m_memConfig[BAGuitar::NUM_MEM_SLOTS]; ///< store the configuration information for each external memory
};
}
#endif /* __LIBMEMORYMANAGEMENT_H */