Skip to content

File qspi.h

File List > external-docs > libDaisy > src > per > qspi.h

Go to the documentation of this file

Source Code

#ifndef DSY_QSPI
#define DSY_QSPI 
#ifndef UNIT_TEST // for unit tests, a dummy implementation

#include <cstdint>
#include "daisy_core.h"
#include "util/hal_map.h"

#define DSY_QSPI_TEXT       \
    __attribute__((section( \
        ".qspiflash_text"))) 
#define DSY_QSPI_DATA       \
    __attribute__((section( \
        ".qspiflash_data"))) 
#define DSY_QSPI_BSS        \
    __attribute__((section( \
        ".qspiflash_bss"))) 
namespace daisy
{
class QSPIHandle
{
  public:
    enum Result
    {
        OK = 0,
        ERR
    };

    enum Status
    {
        GOOD = 0,
        E_HAL_ERROR,
        E_SWITCHING_MODES,
        E_INVALID_MODE,
    };

    struct Config
    {
        enum Device
        {
            IS25LP080D,  
            IS25LP064A,  
            DEVICE_LAST, 
        };

        enum Mode
        {
            MEMORY_MAPPED,    
            INDIRECT_POLLING, 
            MODE_LAST,
        };

        //SCK,  CE# (active low)
        struct
        {
            Pin io0; 
            Pin io1; 
            Pin io2; 
            Pin io3; 
            Pin clk; 
            Pin ncs; 
        } pin_config;

        Device device;
        Mode   mode;
    };

    Result Init(const Config& config);

    const Config& GetConfig() const;

    // Couldn't this just be called before anything else in init? That
    // would make manually calling it unnecessary.
    Result DeInit();

    Result WritePage(uint32_t address, uint32_t size, uint8_t* buffer);

    Result Write(uint32_t address, uint32_t size, uint8_t* buffer);

    Result Erase(uint32_t start_addr, uint32_t end_addr);

    Result EraseSector(uint32_t address);

    Status GetStatus();

    void* GetData(uint32_t offset = 0);

    QSPIHandle() : pimpl_(nullptr) {}
    QSPIHandle(const QSPIHandle& other) = default;
    QSPIHandle& operator=(const QSPIHandle& other) = default;

    class Impl; 
  private:
    Impl* pimpl_;
};

} // namespace daisy

#else

#include <cstdint>
#include "../tests/TestIsolator.h"

namespace daisy
{
class QSPIHandle
{
  public:
    enum Result
    {
        OK = 0,
        ERR
    };

    static Result ResetAndClear()
    {
        testIsolator_.GetStateForCurrentTest()->memory_.clear();
        return Result::OK;
    }


    static Result Write(uint32_t address, uint32_t size, uint8_t* buffer)
    {
        // 256-byte aligned, normalized address value
        uint32_t adjusted_addr = (address) & (uint32_t)(~0xff);
        // Make sure memory is of approriate size
        uint32_t total_bytes = adjusted_addr + size;
        AdaptToSize(total_bytes);
        // Copy data into vector
        uint8_t* dest = testIsolator_.GetStateForCurrentTest()->memory_.data();
        std::copy(&buffer[adjusted_addr],
                  &buffer[adjusted_addr + size],
                  &dest[adjusted_addr]);
        return Result::OK;
    }

    static Result Erase(uint32_t start_addr, uint32_t end_addr)
    {
        uint32_t adjusted_start_addr = (start_addr) & (uint32_t)(~0xff);
        uint32_t adjusted_end_addr   = (end_addr) & (uint32_t)(~0xff);

        // guard addresses
        assert(adjusted_start_addr < kMaxAdjustedAddr);
        assert(adjusted_end_addr < kMaxAdjustedAddr);

        // Make sure vector is of appropriate size
        // size should be at least (adjusted_end_addr)
        AdaptToSize(adjusted_end_addr);
        uint8_t* buff = testIsolator_.GetStateForCurrentTest()->memory_.data();
        // Erases memory by setting all bits to 1
        std::fill(&buff[adjusted_start_addr], &buff[adjusted_end_addr], 0xff);
        return Result::OK;
    }

    static void* GetData(uint32_t offset = 0)
    {
        assert(offset < kMaxAdjustedAddr);
        AdaptToSize(offset + 1); 
        return (void*)(testIsolator_.GetStateForCurrentTest()->memory_.data()
                       + offset);
    }

    static size_t GetCurrentSize()
    {
        return testIsolator_.GetStateForCurrentTest()->memory_.size();
    }

  private:
    static void AdaptToSize(uint32_t required_bytes)
    {
        if(testIsolator_.GetStateForCurrentTest()->memory_.size()
           < required_bytes)
            testIsolator_.GetStateForCurrentTest()->memory_.resize(
                required_bytes, 0x00);
    }
    static constexpr uint32_t kMaxAdjustedAddr = 0x800000;
    struct QSPIState
    {
        // Emulate the byte-memory of the QSPI flash
        std::vector<uint8_t> memory_;
    };
    static TestIsolator<QSPIState> testIsolator_;
};


} // namespace daisy


#endif // ifndef UNIT_TEST

#endif // ifndef DSY_QSPI