mirror of
https://git.intern.spaceteamaachen.de/ALPAKA/driver-w25qxxx.git
synced 2025-08-01 20:21:53 +00:00
Updated implementation for driver
This commit is contained in:
parent
839382790c
commit
517510c204
@ -9,11 +9,73 @@ namespace sta
|
||||
{
|
||||
class W25Qxx
|
||||
{
|
||||
enum class BlockSize
|
||||
{
|
||||
_32KB,
|
||||
_64KB
|
||||
};
|
||||
|
||||
// TODO decide address size at compile time? Use sta/config.hpp?
|
||||
|
||||
union Address32
|
||||
{
|
||||
uint32_t value;
|
||||
uint8_t buffer[4];
|
||||
uint8_t page[3];
|
||||
};
|
||||
|
||||
union Address24
|
||||
{
|
||||
uint32_t value;
|
||||
uint8_t dummy;
|
||||
uint8_t buffer[3];
|
||||
uint8_t page[2];
|
||||
};
|
||||
|
||||
enum class ChipState
|
||||
{
|
||||
NORMAL,
|
||||
POWERED_DOWN
|
||||
};
|
||||
public:
|
||||
W25Qxx(SPIDevice * device);
|
||||
|
||||
uint8_t init();
|
||||
|
||||
uint8_t getChipID();
|
||||
|
||||
uint8_t getManufacturerID();
|
||||
|
||||
uint64_t getUniqueID();
|
||||
|
||||
// TODO: SFDP register?
|
||||
|
||||
/**
|
||||
* @brief Puts the chip into power-down state which significantly reduces power consumption.
|
||||
*
|
||||
* @remarks Every instruction but the releasePowerDown instruction are ignored in this state,
|
||||
* allowing for maximum write protection.
|
||||
*
|
||||
* @return uint8_t Returns 1 if the operation was successful, 0 otherwise.
|
||||
*/
|
||||
uint8_t powerDown();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return uint8_t
|
||||
*/
|
||||
uint8_t releasePowerDown();
|
||||
|
||||
// enable reset
|
||||
|
||||
// reset device
|
||||
|
||||
// Extended address register read / write?
|
||||
|
||||
// Enter 4-Byte address mode
|
||||
|
||||
// Exit 4-Byte address mode
|
||||
public:
|
||||
/*
|
||||
* Status registers.
|
||||
@ -44,6 +106,104 @@ namespace sta
|
||||
* @return bool Returns true if the flash is busy, false otherwise.
|
||||
*/
|
||||
bool isBusy();
|
||||
public:
|
||||
/*
|
||||
* Read / Write operations
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param addr
|
||||
* @param buffer
|
||||
* @param length
|
||||
* @return uint8_t
|
||||
*/
|
||||
uint8_t readData(Address32 address, uint8_t * buffer, size_t length, bool fast = true);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param addr
|
||||
* @param buffer
|
||||
* @param length
|
||||
* @return uint8_t
|
||||
*/
|
||||
uint8_t pageProgram(Address32 address, uint8_t * buffer, size_t length);
|
||||
|
||||
|
||||
public:
|
||||
/*
|
||||
* Erase operations
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Sets all memory within a specified sector (4 KByte) to 1s.
|
||||
*
|
||||
* @remarks Afterwards, the device won't accept any instructions for a duration T_SE. This can be checked
|
||||
* by reading the busy bit.
|
||||
*
|
||||
* @param address The address of the sector to erase.
|
||||
* @return bool Returns 1 if the operation was successful, 0 otherwise.
|
||||
*/
|
||||
uint8_t sectorErase(Address32 address);
|
||||
|
||||
/**
|
||||
* @brief Sets all memory within a specified block (32/64 KByte) to 1s.
|
||||
*
|
||||
* @remarks Afterwards, the device won't accept any instructions for a duration T_SE. This can be checked
|
||||
* by reading the busy bit.
|
||||
*
|
||||
* @param address The address of the block to erase.
|
||||
* @param blockSize The size of the block (32KByte vs 64KByte)
|
||||
* @return uint8_t Returns 1 if the operation was successful, 0 otherwise.
|
||||
*/
|
||||
uint8_t blockErase(Address32 address, BlockSize blockSize);
|
||||
|
||||
/**
|
||||
* @brief Sets all memory on the chip to 1s.
|
||||
*
|
||||
* @return uint8_t Returns 1 if the operation was successful, 0 otherwise.
|
||||
*/
|
||||
uint8_t chipErase();
|
||||
|
||||
/**
|
||||
* @brief Suspends an ongoing sector or block erase operation.
|
||||
*
|
||||
* @remarks Chip erase operations cannot be suspended.
|
||||
*
|
||||
* @return uin8t_t Returns 1 if the operation was successful, 0 otherwise.
|
||||
*/
|
||||
uint8_t suspendErase();
|
||||
|
||||
/**
|
||||
* @brief Resumes a suspended sector or block erase operation.
|
||||
*
|
||||
* @return uint8_t Returns 1 if the operation was successful, 0 otherwise.
|
||||
*/
|
||||
uint8_t resumeErase();
|
||||
|
||||
// TODO: Read SUS bit
|
||||
public:
|
||||
// Erase security registers
|
||||
|
||||
// Program security registers
|
||||
|
||||
// Read security registers
|
||||
|
||||
// Indiv Block / Sector lock
|
||||
|
||||
// Indiv Block / Sector unlock
|
||||
|
||||
// Indiv Block / Sector lock read
|
||||
|
||||
// Global Block / Sector lock
|
||||
|
||||
// Global Block / Sector unlock
|
||||
private:
|
||||
uint8_t busWrite(uint8_t instruction, const uint8_t * data = nullptr, size_t length = 0, uint8_t * arguments = nullptr, size_t arg_length = 0);
|
||||
|
||||
uint8_t busRead(uint8_t instruction, uint8_t * data, size_t length, uint8_t * arguments = nullptr, size_t arg_length = 0);
|
||||
|
||||
/**
|
||||
* @brief Checks if the flash is write enabled.
|
||||
@ -51,24 +211,16 @@ namespace sta
|
||||
* @return bool Returns true if the flash is write enabled, false otherwise.
|
||||
*/
|
||||
bool isWriteEnabled();
|
||||
|
||||
public:
|
||||
|
||||
uint8_t readData(const uint8_t * addr, uint8_t * buffer, size_t length);
|
||||
|
||||
uint8_t pageProgram(const uint8_t * addr, uint8_t * buffer, size_t length);
|
||||
private:
|
||||
uint8_t busWrite(uint8_t instruction, const uint8_t * data = nullptr, size_t length = 0);
|
||||
|
||||
uint8_t busRead(uint8_t instruction, uint8_t * data, size_t length);
|
||||
|
||||
|
||||
uint8_t writeEnable();
|
||||
|
||||
uint8_t writeDisable();
|
||||
|
||||
uint8_t writeVolatileEnable();
|
||||
|
||||
uint8_t writeDisable();
|
||||
|
||||
private:
|
||||
SPIDevice * device_;
|
||||
ChipState state_;
|
||||
};
|
||||
} // namespace sta
|
||||
|
||||
|
@ -38,10 +38,12 @@
|
||||
#define W25QXX_PAGE_PROGAM 0x02
|
||||
#define W25QXX_QUAD_PAGE_PROGAM 0x32
|
||||
|
||||
#define W25QXX_SECTOR_ERASE 0x20
|
||||
#define W25QXX_BLOCK_ERASE 0xD8
|
||||
#define W25QXX_SECTOR_ERASE 0x21
|
||||
#define W25QXX_BLOCK_ERASE_32_KB 0x52
|
||||
#define W25QXX_BLOCK_ERASE_64_KB 0xD8
|
||||
|
||||
#define W25QXX_FAST_READ 0x03
|
||||
#define W25QXX_READ 0x03
|
||||
#define W25QXX_FAST_READ 0x0B
|
||||
#define W25QXX_FAST_READ_DUAL_OUT 0x3B
|
||||
#define W25QXX_FAST_READ_QUAD_OUT 0x6B
|
||||
#define W25QXX_SFDP_REG 0x5A
|
||||
|
142
src/w25qxx.cpp
142
src/w25qxx.cpp
@ -1,12 +1,16 @@
|
||||
#include <sta/sensors/w25qxx.hpp>
|
||||
|
||||
#include <string.h>
|
||||
#include <sta/debug/assert.hpp>
|
||||
|
||||
|
||||
namespace sta
|
||||
{
|
||||
W25Qxx::W25Qxx(SPIDevice * device)
|
||||
: device_{device}
|
||||
: device_{device},
|
||||
state_{ChipState::NORMAL}
|
||||
{
|
||||
|
||||
STA_ASSERT(device != nullptr);
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::init()
|
||||
@ -16,6 +20,41 @@ namespace sta
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::getChipID()
|
||||
{
|
||||
uint8_t buffer[4];
|
||||
busRead(W25QXX_RELEASE_POWER_DOWN, buffer, 3);
|
||||
|
||||
return buffer[3];
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::getManufacturerID()
|
||||
{
|
||||
Address24 address = {0};
|
||||
|
||||
uint8_t id;
|
||||
busRead(W25QXX_JEDEC_ID, &id, 1, address.buffer, 3);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
uint64_t W25Qxx::getUniqueID()
|
||||
{
|
||||
uint8_t dummy[4];
|
||||
uint8_t id[8];
|
||||
|
||||
busRead(W25QXX_READ_UNIQUE_ID, id, 8, dummy, 4);
|
||||
|
||||
uint64_t id_complete;
|
||||
|
||||
for (size_t i; i < 8; i++)
|
||||
{
|
||||
id_complete |= id[i] << (7-i) * 8;
|
||||
}
|
||||
|
||||
return id_complete;
|
||||
}
|
||||
|
||||
bool W25Qxx::isBusy()
|
||||
{
|
||||
uint8_t status = 0;
|
||||
@ -24,26 +63,46 @@ namespace sta
|
||||
return (0x01 & status) == 0x01;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
|
||||
uint8_t W25Qxx::readData(const uint8_t * addr, uint8_t * buffer, size_t length)
|
||||
uint8_t W25Qxx::readData(Address32 addr, uint8_t * buffer, size_t length, bool fast /* = true */)
|
||||
{
|
||||
device_->beginTransmission();
|
||||
|
||||
const uint8_t instruction = W25QXX_FAST_READ;
|
||||
uint8_t instruction = fast ? W25QXX_FAST_READ : W25QXX_FAST_READ;
|
||||
device_->transfer(&instruction, 1);
|
||||
device_->transfer(addr, 3);
|
||||
|
||||
// In fast mode we have to send a 8 dummy clock cycles first.
|
||||
if (fast)
|
||||
{
|
||||
uint8_t dummy = 0;
|
||||
device_->transfer(&dummy, 1);
|
||||
}
|
||||
|
||||
device_->transfer(addr.buffer, sizeof(addr));
|
||||
device_->receive(buffer, length);
|
||||
device_->endTransmission();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::busWrite(uint8_t instruction, const uint8_t * data /* = nullptr */, size_t length /* = 0 */)
|
||||
uint8_t W25Qxx::pageProgram(Address32 addr, uint8_t * buffer, size_t length)
|
||||
{
|
||||
if (!writeEnable())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: sizeof(addr)-1 doesn't work for 24 bit addresses.
|
||||
return busWrite(W25QXX_PAGE_PROGAM, buffer, length, addr.page, sizeof(addr)-1);
|
||||
|
||||
// TODO: Does this reset the writeEnable bit?
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::busWrite(uint8_t instruction, const uint8_t * data /* = nullptr */, size_t length /* = 0 */, uint8_t * arguments /* = nullptr */, size_t arg_length /* = 0 */)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::busRead(uint8_t instruction, uint8_t * data, size_t length)
|
||||
uint8_t W25Qxx::busRead(uint8_t instruction, uint8_t * data, size_t length, uint8_t * arguments /* = nullptr */, size_t arg_length /* = 0 */)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@ -118,19 +177,70 @@ namespace sta
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::pageProgram(const uint8_t * addr, uint8_t * buffer, size_t length)
|
||||
bool W25Qxx::isWriteEnabled()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::sectorErase(Address32 address)
|
||||
{
|
||||
if (!writeEnable())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
device_->beginTransmission();
|
||||
uint8_t instruction = W25QXX_PAGE_PROGAM;
|
||||
device_->transfer(&instruction, 1);
|
||||
device_->transfer(buffer, length);
|
||||
device_->endTransmission();
|
||||
return busWrite(W25QXX_SECTOR_ERASE, address.buffer, sizeof(address));
|
||||
}
|
||||
|
||||
return 1;
|
||||
uint8_t W25Qxx::blockErase(Address32 address, BlockSize blockSize)
|
||||
{
|
||||
if (!writeEnable())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (blockSize == BlockSize::_32KB)
|
||||
{
|
||||
return busWrite(W25QXX_BLOCK_ERASE_32_KB, address.buffer, sizeof(address));
|
||||
}
|
||||
else
|
||||
{
|
||||
return busWrite(W25QXX_BLOCK_ERASE_64_KB, address.buffer, sizeof(address));
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::chipErase()
|
||||
{
|
||||
if (!writeEnable())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return busWrite(W25QXX_CHIP_ERASE);
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::suspendErase()
|
||||
{
|
||||
return busWrite(W25QXX_ERASE_SUSPEND_PROG);
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::resumeErase()
|
||||
{
|
||||
return busWrite(W25QXX_ERASE_RESUME_PROG);
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::powerDown()
|
||||
{
|
||||
return busWrite(W25QXX_POWER_DOWN);
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::releasePowerDown()
|
||||
{
|
||||
if (state_ == ChipState::POWERED_DOWN)
|
||||
{
|
||||
return busWrite(W25QXX_RELEASE_POWER_DOWN);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace sta
|
Loading…
x
Reference in New Issue
Block a user