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