-
Notifications
You must be signed in to change notification settings - Fork 143
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[driver] Add BdSpiStackFlash contiguous memory
- Loading branch information
1 parent
ebe4114
commit a1ad2a0
Showing
3 changed files
with
321 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
125 changes: 125 additions & 0 deletions
125
src/modm/driver/storage/block_device_spistack_flash.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
// coding: utf-8 | ||
/* | ||
* Copyright (c) 2018, Raphael Lehmann | ||
* | ||
* This file is part of the modm project. | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
// ---------------------------------------------------------------------------- | ||
|
||
#ifndef MODM_BLOCK_DEVICE_SPISTACK_FLASH_HPP | ||
#define MODM_BLOCK_DEVICE_SPISTACK_FLASH_HPP | ||
|
||
#include <algorithm> | ||
#include <cstdlib> | ||
|
||
#include <modm/architecture/interface/block_device.hpp> | ||
#include <modm/processing/resumable.hpp> | ||
|
||
namespace modm | ||
{ | ||
|
||
/** | ||
* \brief SpiStack homogenoues memory | ||
* | ||
* The `read()`, `erase()`,`program()` and `write()` methodes wait for | ||
* the chip to finish writing to the flash. | ||
* | ||
* \tparam SpiBlockDevice Base SPI block device of the homogenous stack | ||
* | ||
* \ingroup modm_driver_block_device_spi_stack_flash | ||
* \author Rasmus Kleist Hørlyck Sørensen | ||
*/ | ||
template <typename SpiBlockDevice, uint8_t DieCount> | ||
class BdSpiStackFlash : public modm::BlockDevice, protected NestedResumable<3> | ||
{ | ||
public: | ||
/// Initializes the storage hardware | ||
modm::ResumableResult<bool> | ||
initialize(); | ||
|
||
/// Deinitializes the storage hardware | ||
modm::ResumableResult<bool> | ||
deinitialize(); | ||
|
||
/** Read data from one or more blocks | ||
* | ||
* @param buffer Buffer to read data into | ||
* @param address Address to begin reading from | ||
* @param size Size to read in bytes (multiple of read block size) | ||
* @return True on success | ||
*/ | ||
modm::ResumableResult<bool> | ||
read(uint8_t* buffer, bd_address_t address, bd_size_t size); | ||
|
||
/** Program blocks with data | ||
* | ||
* Any block has to be erased prior to being programmed | ||
* | ||
* @param buffer Buffer of data to write to blocks | ||
* @param address Address of first block to begin writing to | ||
* @param size Size to write in bytes (multiple of read block size) | ||
* @return True on success | ||
*/ | ||
modm::ResumableResult<bool> | ||
program(const uint8_t* buffer, bd_address_t address, bd_size_t size); | ||
|
||
/** Erase blocks | ||
* | ||
* The state of an erased block is undefined until it has been programmed | ||
* | ||
* @param address Address of block to begin erasing | ||
* @param size Size to erase in bytes (multiple of read block size) | ||
* @return True on success | ||
*/ | ||
modm::ResumableResult<bool> | ||
erase(bd_address_t address, bd_size_t size); | ||
|
||
/** Writes data to one or more blocks after erasing them | ||
* | ||
* The blocks are erased prior to being programmed | ||
* | ||
* @param buffer Buffer of data to write to blocks | ||
* @param address Address of first block to begin writing to | ||
* @param size Size to write in bytes (multiple of read block size) | ||
* @return True on success | ||
*/ | ||
modm::ResumableResult<bool> | ||
write(const uint8_t* buffer, bd_address_t address, bd_size_t size); | ||
|
||
public: | ||
/** Check if device is busy | ||
* | ||
* @return True if any die in the stack is busy. | ||
*/ | ||
modm::ResumableResult<bool> | ||
isBusy(); | ||
|
||
/** This function can be used in another resumable function | ||
* to wait until the flash operation is finished. | ||
*/ | ||
modm::ResumableResult<void> | ||
waitWhileBusy(); | ||
|
||
public: | ||
static constexpr bd_size_t BlockSizeRead = SpiBlockDevice::BlockSizeRead; | ||
static constexpr bd_size_t BlockSizeWrite = SpiBlockDevice::BlockSizeWrite; | ||
static constexpr bd_size_t BlockSizeErase = SpiBlockDevice::BlockSizeErase; | ||
static constexpr bd_size_t DieSize = SpiBlockDevice::DeviceSize; | ||
static constexpr bd_size_t DeviceSize = DieCount * DieSize; | ||
|
||
private: | ||
std::ldiv_t dv; | ||
uint32_t index; | ||
uint8_t currentDie; | ||
SpiBlockDevice spiBlockDevice; | ||
}; | ||
|
||
} // namespace modm | ||
|
||
#include "block_device_spistack_flash_impl.hpp" | ||
|
||
#endif // MODM_BLOCK_DEVICE_SPISTACK_FLASH_HPP |
180 changes: 180 additions & 0 deletions
180
src/modm/driver/storage/block_device_spistack_flash_impl.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
// coding: utf-8 | ||
/* | ||
* Copyright (c) 2023, Rasmus Kleist Hørlyck Sørensen | ||
* | ||
* This file is part of the modm project. | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
// ---------------------------------------------------------------------------- | ||
|
||
#ifndef MODM_BLOCK_DEVICE_SPISTACK_FLASH_HPP | ||
#error "Don't include this file directly, use 'block_device_spistack_flash.hpp' instead!" | ||
#endif | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
template <typename SpiBlockDevice, uint8_t DieCount> | ||
modm::ResumableResult<bool> | ||
modm::BdSpiStackFlash<SpiBlockDevice, DieCount>::initialize() | ||
{ | ||
RF_BEGIN(); | ||
|
||
if (RF_CALL(spiBlockDevice.initialize())) { | ||
RF_CALL(spiBlockDevice.selectDie(currentDie = 0x00)); | ||
RF_RETURN(true); | ||
} | ||
|
||
RF_END_RETURN(false); | ||
} | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
template <typename SpiBlockDevice, uint8_t DieCount> | ||
modm::ResumableResult<bool> | ||
modm::BdSpiStackFlash<SpiBlockDevice, DieCount>::deinitialize() | ||
{ | ||
RF_BEGIN(); | ||
RF_END_RETURN_CALL(spiBlockDevice.deinitialize()); | ||
} | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
template <typename SpiBlockDevice, uint8_t DieCount> | ||
modm::ResumableResult<bool> | ||
modm::BdSpiStackFlash<SpiBlockDevice, DieCount>::read(uint8_t* buffer, bd_address_t address, bd_size_t size) | ||
{ | ||
RF_BEGIN(); | ||
|
||
if((size == 0) || (size % BlockSizeRead != 0) || (address + size > DeviceSize)) { | ||
RF_RETURN(false); | ||
} | ||
|
||
index = 0; | ||
while (index < size) { | ||
dv = std::ldiv(index + address, DieSize); // dv.quot = die #ID, dv.rem = die address | ||
if (currentDie != dv.quot) { | ||
RF_CALL(spiBlockDevice.selectDie(currentDie = dv.quot)); | ||
} | ||
if (RF_CALL(spiBlockDevice.read(&buffer[index], dv.rem, std::min(size - index, DieSize - dv.rem)))) { | ||
index += DieSize - dv.rem; // size - index <= DieSize - dv.rem only on last iteration! | ||
} else { | ||
RF_RETURN(false); | ||
} | ||
} | ||
|
||
RF_END_RETURN(true); | ||
} | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
template <typename SpiBlockDevice, uint8_t DieCount> | ||
modm::ResumableResult<bool> | ||
modm::BdSpiStackFlash<SpiBlockDevice, DieCount>::program(const uint8_t* buffer, bd_address_t address, bd_size_t size) | ||
{ | ||
RF_BEGIN(); | ||
|
||
if((size == 0) || (size % BlockSizeWrite != 0) || (address + size > DeviceSize)) { | ||
RF_RETURN(false); | ||
} | ||
|
||
index = 0; | ||
while (index < size) { | ||
dv = std::ldiv(index + address, DieSize); // dv.quot = die #ID, dv.rem = die address | ||
if (currentDie != dv.quot) { | ||
RF_CALL(spiBlockDevice.selectDie(currentDie = dv.quot)); | ||
} | ||
if (RF_CALL(spiBlockDevice.program(&buffer[index], dv.rem, std::min(size - index, DieSize - dv.rem)))) { | ||
index += DieSize - dv.rem; // size - index <= DieSize - dv.rem only on last iteration! | ||
} else { | ||
RF_RETURN(false); | ||
} | ||
} | ||
|
||
RF_END_RETURN(true); | ||
} | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
template <typename SpiBlockDevice, uint8_t DieCount> | ||
modm::ResumableResult<bool> | ||
modm::BdSpiStackFlash<SpiBlockDevice, DieCount>::erase(bd_address_t address, bd_size_t size) | ||
{ | ||
RF_BEGIN(); | ||
|
||
if((size == 0) || (size % BlockSizeErase != 0) || (address + size > DeviceSize)) { | ||
RF_RETURN(false); | ||
} | ||
|
||
index = 0; | ||
while (index < size) { | ||
dv = std::ldiv(index + address, DieSize); // dv.quot = die #ID, dv.rem = die address | ||
if (currentDie != dv.quot) { | ||
RF_CALL(spiBlockDevice.selectDie(currentDie = dv.quot)); | ||
} | ||
if (RF_CALL(spiBlockDevice.erase(dv.rem, std::min(size - index, DieSize - dv.rem)))) { | ||
index += DieSize - dv.rem; // size - index <= DieSize - dv.rem only on last iteration! | ||
} else { | ||
RF_RETURN(false); | ||
} | ||
} | ||
|
||
RF_END_RETURN(true); | ||
} | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
template <typename SpiBlockDevice, uint8_t DieCount> | ||
modm::ResumableResult<bool> | ||
modm::BdSpiStackFlash<SpiBlockDevice, DieCount>::write(const uint8_t* buffer, bd_address_t address, bd_size_t size) | ||
{ | ||
RF_BEGIN(); | ||
|
||
if((size == 0) || (size % BlockSizeErase != 0) || (size % BlockSizeWrite != 0) || (address + size > DeviceSize)) { | ||
RF_RETURN(false); | ||
} | ||
|
||
if(!RF_CALL(this->erase(address, size))) { | ||
RF_RETURN(false); | ||
} | ||
|
||
if(!RF_CALL(this->program(buffer, address, size))) { | ||
RF_RETURN(false); | ||
} | ||
|
||
RF_END_RETURN(true); | ||
} | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
template <typename SpiBlockDevice, uint8_t DieCount> | ||
modm::ResumableResult<bool> | ||
modm::BdSpiStackFlash<SpiBlockDevice, DieCount>::isBusy() | ||
{ | ||
RF_BEGIN(); | ||
|
||
currentDie = DieCount; | ||
while (currentDie > 0) { | ||
RF_CALL(spiBlockDevice.selectDie(--currentDie)); | ||
if (RF_CALL(spiBlockDevice.isBusy())) { | ||
RF_RETURN(true); | ||
} | ||
} | ||
|
||
RF_END_RETURN(false); | ||
} | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
template <typename SpiBlockDevice, uint8_t DieCount> | ||
modm::ResumableResult<void> | ||
modm::BdSpiStackFlash<SpiBlockDevice, DieCount>::waitWhileBusy() | ||
{ | ||
RF_BEGIN(); | ||
while(RF_CALL(isBusy())) { | ||
RF_YIELD(); | ||
} | ||
RF_END(); | ||
} |