/**************************************************************************//** * @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=nullptr, 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); void readDmaBufferContents(uint8_t *dest, size_t numBytes, size_t bufferOffset = 0); /// 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; } /// 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 /// @returns true on success, otherwise false on error bool requestMemory(ExtMemSlot *slot, float delayMilliseconds, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0, bool useDma = true); /// 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 /// @returns true on success, otherwise false on error bool requestMemory(ExtMemSlot *slot, size_t sizeBytes, BAGuitar::MemSelect mem = BAGuitar::MemSelect::MEM0, bool useDma = true); 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 */