mirror of
https://git.intern.spaceteamaachen.de/ALPAKA/driver-w25qxxx.git
synced 2025-08-02 04:21:54 +00:00
Address mode updating works as intended, successful chip erase, read and write
This commit is contained in:
parent
ebbcd79fb9
commit
b28e15daff
@ -7,41 +7,59 @@
|
||||
|
||||
namespace sta
|
||||
{
|
||||
class W25Qxx
|
||||
{
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
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];
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
enum class ChipState
|
||||
{
|
||||
NORMAL,
|
||||
POWERED_DOWN
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
enum class AddressMode
|
||||
{
|
||||
_24BIT,
|
||||
_32BIT
|
||||
};
|
||||
|
||||
class W25Qxx
|
||||
{
|
||||
public:
|
||||
W25Qxx(SPIDevice * device);
|
||||
/**
|
||||
* @brief Construct a new W25Qxx object
|
||||
*
|
||||
* @param device
|
||||
* @param addrMode
|
||||
*/
|
||||
W25Qxx(SPIDevice * device, AddressMode addrMode = AddressMode::_24BIT);
|
||||
|
||||
uint8_t init();
|
||||
|
||||
/**
|
||||
* @brief Set the Address Mode object
|
||||
*
|
||||
* @param addrMode
|
||||
* @return uint8_t
|
||||
*/
|
||||
uint8_t setAddressMode(AddressMode addrMode);
|
||||
|
||||
AddressMode getAddressMode();
|
||||
|
||||
uint8_t getChipID();
|
||||
|
||||
uint8_t getManufacturerID();
|
||||
@ -119,7 +137,7 @@ namespace sta
|
||||
* @param length
|
||||
* @return uint8_t
|
||||
*/
|
||||
uint8_t readData(Address32 address, uint8_t * buffer, size_t length, bool fast = true);
|
||||
uint8_t readData(uint32_t address, uint8_t * buffer, size_t length, bool fast = true);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
@ -129,7 +147,7 @@ namespace sta
|
||||
* @param length
|
||||
* @return uint8_t
|
||||
*/
|
||||
uint8_t pageProgram(Address32 address, uint8_t * buffer, size_t length);
|
||||
uint8_t pageProgram(uint32_t address, uint8_t * buffer, size_t length);
|
||||
|
||||
|
||||
public:
|
||||
@ -146,7 +164,7 @@ namespace sta
|
||||
* @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);
|
||||
uint8_t sectorErase(uint32_t address);
|
||||
|
||||
/**
|
||||
* @brief Sets all memory within a specified block (32/64 KByte) to 1s.
|
||||
@ -158,7 +176,7 @@ namespace sta
|
||||
* @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);
|
||||
uint8_t blockErase(uint32_t address, BlockSize blockSize);
|
||||
|
||||
/**
|
||||
* @brief Sets all memory on the chip to 1s.
|
||||
@ -201,8 +219,28 @@ namespace sta
|
||||
|
||||
// Global Block / Sector unlock
|
||||
private:
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param instruction
|
||||
* @param data
|
||||
* @param length
|
||||
* @param arguments
|
||||
* @param arg_length
|
||||
* @return uint8_t
|
||||
*/
|
||||
uint8_t busWrite(uint8_t instruction, const uint8_t * data = nullptr, size_t length = 0, uint8_t * arguments = nullptr, size_t arg_length = 0);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param instruction
|
||||
* @param data
|
||||
* @param length
|
||||
* @param arguments
|
||||
* @param arg_length
|
||||
* @return uint8_t
|
||||
*/
|
||||
uint8_t busRead(uint8_t instruction, uint8_t * data, size_t length, uint8_t * arguments = nullptr, size_t arg_length = 0);
|
||||
|
||||
/**
|
||||
@ -221,6 +259,7 @@ namespace sta
|
||||
private:
|
||||
SPIDevice * device_;
|
||||
ChipState state_;
|
||||
AddressMode addrMode_;
|
||||
};
|
||||
} // namespace sta
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef STA_SENSORS_W25QXX_DEFS_HPP
|
||||
#define STA_SENSORS_W25QXX_DEFS_HPP
|
||||
|
||||
// Enable 4 Byte address mode (for W25Q512)
|
||||
#define W25QXX_4_BYTE_ADDR_ENABLE 0xB7
|
||||
|
||||
// W25Qxx-specific instructions
|
||||
#define W25QXX_WRITE_ENABLE 0x06
|
||||
@ -26,7 +28,6 @@
|
||||
|
||||
// ID reading
|
||||
#define W25QXX_DEVICE_ID 0x90
|
||||
#define W25QXX_JEDEC_ID 0x9F
|
||||
#define W25QXX_READ_UNIQUE_ID 0x4B
|
||||
|
||||
#define W25QXX_GLOBAL_BLOCK_LOCK 0x7E
|
||||
@ -56,7 +57,8 @@
|
||||
#define W25QXX_INDIV_BLOCK_UNLOCK 0x39
|
||||
#define W25QXX_READ_BLOCK_LOCK 0x3D
|
||||
|
||||
#define W25QXX_FAST_READ_DUAL
|
||||
|
||||
#define W25QXX_DEVICE_ID_RESULT 0xEF
|
||||
|
||||
|
||||
#endif // STA_SENSORS_W25QXX_DEFS_HPP
|
194
src/w25qxx.cpp
194
src/w25qxx.cpp
@ -8,20 +8,56 @@
|
||||
|
||||
namespace sta
|
||||
{
|
||||
W25Qxx::W25Qxx(SPIDevice * device)
|
||||
W25Qxx::W25Qxx(SPIDevice * device, AddressMode addrMode /* = AddressMode::_24BIT */)
|
||||
: device_{device},
|
||||
state_{ChipState::NORMAL}
|
||||
state_{ChipState::POWERED_DOWN},
|
||||
addrMode_{addrMode}
|
||||
{
|
||||
STA_ASSERT(device != nullptr);
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::init()
|
||||
{
|
||||
// Check if the chip returns the correct device id.
|
||||
if (getManufacturerID() != W25QXX_DEVICE_ID_RESULT)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If requested, tell the flash chip to use 32 bit addresses.
|
||||
if (addrMode_ == AddressMode::_32BIT)
|
||||
{
|
||||
if (!setAddressMode(AddressMode::_32BIT))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!releasePowerDown())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::setAddressMode(AddressMode addrMode)
|
||||
{
|
||||
busWrite(W25QXX_4_BYTE_ADDR_ENABLE);
|
||||
|
||||
while (isBusy()) {}
|
||||
|
||||
return getAddressMode() == addrMode;
|
||||
}
|
||||
|
||||
AddressMode W25Qxx::getAddressMode()
|
||||
{
|
||||
uint8_t status;
|
||||
readStatusRegister(3, &status);
|
||||
|
||||
return status && 0x01 == 0x01 ? AddressMode::_32BIT : AddressMode::_24BIT;
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::getChipID()
|
||||
{
|
||||
uint8_t buffer[4];
|
||||
@ -35,7 +71,7 @@ namespace sta
|
||||
uint8_t dummy[3] = {0, 0, 0};
|
||||
uint8_t id;
|
||||
|
||||
busRead(W25QXX_JEDEC_ID, &id, 1, dummy, 3);
|
||||
busRead(W25QXX_DEVICE_ID, &id, 1, dummy, 3);
|
||||
|
||||
return id;
|
||||
}
|
||||
@ -45,8 +81,6 @@ namespace sta
|
||||
uint8_t dummy[4];
|
||||
uint8_t id[8];
|
||||
|
||||
STA_DEBUG_PRINTLN("Before crash?");
|
||||
|
||||
busRead(W25QXX_READ_UNIQUE_ID, id, 8, dummy, 4);
|
||||
|
||||
uint64_t id_complete = 0;
|
||||
@ -64,41 +98,75 @@ namespace sta
|
||||
uint8_t status = 0;
|
||||
readStatusRegister(1, &status);
|
||||
|
||||
return (0x01 & status) == 0x01;
|
||||
return (0x01 && status) == 0x01;
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::readData(Address32 addr, uint8_t * buffer, size_t length, bool fast /* = true */)
|
||||
uint8_t W25Qxx::readData(uint32_t address, uint8_t * buffer, size_t length, bool fast /* = true */)
|
||||
{
|
||||
device_->beginTransmission();
|
||||
|
||||
uint8_t instruction = fast ? W25QXX_FAST_READ : W25QXX_FAST_READ;
|
||||
device_->transfer(&instruction, 1);
|
||||
uint8_t instruction = fast ? W25QXX_FAST_READ : W25QXX_READ;
|
||||
|
||||
// In fast mode we have to send a 8 dummy clock cycles first.
|
||||
if (fast)
|
||||
{
|
||||
uint8_t dummy = 0;
|
||||
device_->transfer(&dummy, 1);
|
||||
// TODO
|
||||
}
|
||||
|
||||
device_->transfer(addr.buffer, sizeof(addr));
|
||||
device_->receive(buffer, length);
|
||||
device_->endTransmission();
|
||||
while (isBusy()) {}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::pageProgram(Address32 addr, uint8_t * buffer, size_t length)
|
||||
// Depending on address mode, send 3 bytes or 4 bytes.
|
||||
if (addrMode_ == AddressMode::_32BIT)
|
||||
{
|
||||
uint8_t addrBuffer[4] = {
|
||||
(uint8_t) (address << 24),
|
||||
(uint8_t) (address << 16),
|
||||
(uint8_t) (address << 8),
|
||||
(uint8_t) (address)
|
||||
};
|
||||
|
||||
return busRead(instruction, buffer, length, addrBuffer, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t addrBuffer[3] = {
|
||||
(uint8_t) (address << 16),
|
||||
(uint8_t) (address << 8),
|
||||
(uint8_t) (address)
|
||||
};
|
||||
|
||||
return busRead(instruction, buffer, length, addrBuffer, 4);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::pageProgram(uint32_t address, uint8_t * buffer, size_t length)
|
||||
{
|
||||
while (isBusy()) {}
|
||||
|
||||
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);
|
||||
if (addrMode_ == AddressMode::_32BIT)
|
||||
{
|
||||
uint8_t addrBuffer[4] = {
|
||||
(uint8_t) (address << 24),
|
||||
(uint8_t) (address << 16),
|
||||
(uint8_t) (address << 8),
|
||||
(uint8_t) (address)
|
||||
};
|
||||
|
||||
// TODO: Does this reset the writeEnable bit?
|
||||
return busWrite(W25QXX_PAGE_PROGAM, buffer, length, addrBuffer, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t addrBuffer[3] = {
|
||||
(uint8_t) (address << 16),
|
||||
(uint8_t) (address << 8),
|
||||
(uint8_t) (address)
|
||||
};
|
||||
|
||||
return busWrite(W25QXX_PAGE_PROGAM, buffer, length, addrBuffer, 4);
|
||||
}
|
||||
}
|
||||
|
||||
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 */)
|
||||
@ -114,8 +182,11 @@ namespace sta
|
||||
device_->transfer(arguments, arg_length);
|
||||
}
|
||||
|
||||
// Send the actual data bytes.
|
||||
// If necessary, send the actual data bytes.
|
||||
if (data != nullptr && length != 0)
|
||||
{
|
||||
device_->transfer(data, length);
|
||||
}
|
||||
|
||||
device_->endTransmission();
|
||||
|
||||
@ -126,13 +197,9 @@ namespace sta
|
||||
{
|
||||
device_->beginTransmission();
|
||||
|
||||
STA_DEBUG_PRINTLN("MAYBE HERE?");
|
||||
|
||||
// Send the instruction.
|
||||
device_->transfer(instruction);
|
||||
|
||||
STA_DEBUG_PRINTLN("OR HERE?");
|
||||
|
||||
// If requested, send argument bytes before receiving the actual data.
|
||||
if (arguments != nullptr && arg_length != 0)
|
||||
{
|
||||
@ -144,8 +211,6 @@ namespace sta
|
||||
|
||||
device_->endTransmission();
|
||||
|
||||
STA_DEBUG_PRINTLN("STILL ALIVE?");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -221,34 +286,73 @@ namespace sta
|
||||
|
||||
bool W25Qxx::isWriteEnabled()
|
||||
{
|
||||
|
||||
return true; // TODO
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::sectorErase(Address32 address)
|
||||
uint8_t W25Qxx::sectorErase(uint32_t address)
|
||||
{
|
||||
if (!writeEnable())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return busWrite(W25QXX_SECTOR_ERASE, address.buffer, sizeof(address));
|
||||
}
|
||||
if (addrMode_ == AddressMode::_32BIT)
|
||||
{
|
||||
uint8_t addrBuffer[4] = {
|
||||
(uint8_t) (address << 24),
|
||||
(uint8_t) (address << 16),
|
||||
(uint8_t) (address << 8),
|
||||
(uint8_t) (address)
|
||||
};
|
||||
|
||||
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));
|
||||
return busWrite(W25QXX_SECTOR_ERASE, addrBuffer, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
return busWrite(W25QXX_BLOCK_ERASE_64_KB, address.buffer, sizeof(address));
|
||||
uint8_t addrBuffer[3] = {
|
||||
(uint8_t) (address << 16),
|
||||
(uint8_t) (address << 8),
|
||||
(uint8_t) (address)
|
||||
};
|
||||
|
||||
return busWrite(W25QXX_SECTOR_ERASE, addrBuffer, 3);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::blockErase(uint32_t address, BlockSize blockSize)
|
||||
{
|
||||
if (!writeEnable())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t instruction = blockSize == BlockSize::_32KB ? W25QXX_BLOCK_ERASE_32_KB : W25QXX_BLOCK_ERASE_64_KB;
|
||||
|
||||
if (addrMode_ == AddressMode::_32BIT)
|
||||
{
|
||||
uint8_t addrBuffer[4] = {
|
||||
(uint8_t) (address << 24),
|
||||
(uint8_t) (address << 16),
|
||||
(uint8_t) (address << 8),
|
||||
(uint8_t) (address)
|
||||
};
|
||||
|
||||
return busWrite(instruction, addrBuffer, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t addrBuffer[3] = {
|
||||
(uint8_t) (address << 16),
|
||||
(uint8_t) (address << 8),
|
||||
(uint8_t) (address)
|
||||
};
|
||||
|
||||
return busWrite(instruction, addrBuffer, 3);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t W25Qxx::chipErase()
|
||||
|
Loading…
x
Reference in New Issue
Block a user