kopia lustrzana https://github.com/OpenRTX/OpenRTX
NVM: deeply restructured W25Qx driver
Refactored the W25Qx driver in order to make it an SPI device conformant to the nvmDevice driver interface. Removed the read/write/erase functions.pull/292/head
rodzic
565a056e82
commit
a4db8d2242
|
@ -37,14 +37,6 @@
|
||||||
#define CMD_PDWN 0xB9 /* Power down */
|
#define CMD_PDWN 0xB9 /* Power down */
|
||||||
#define CMD_ECHIP 0xC7 /* Full chip erase */
|
#define CMD_ECHIP 0xC7 /* Full chip erase */
|
||||||
|
|
||||||
/*
|
|
||||||
* Target-specific SPI interface functions, their implementation can be found
|
|
||||||
* in source files "spiFlash_xxx.c"
|
|
||||||
*/
|
|
||||||
extern uint8_t spiFlash_SendRecv(uint8_t val);
|
|
||||||
extern void spiFlash_init();
|
|
||||||
extern void spiFlash_terminate();
|
|
||||||
|
|
||||||
static const size_t PAGE_SIZE = 256;
|
static const size_t PAGE_SIZE = 256;
|
||||||
static const size_t SECT_SIZE = 4096;
|
static const size_t SECT_SIZE = 4096;
|
||||||
|
|
||||||
|
@ -56,7 +48,7 @@ static const size_t SECT_SIZE = 4096;
|
||||||
* @param timeout: wait timeout, in ms.
|
* @param timeout: wait timeout, in ms.
|
||||||
* @return zero on success, -EIO if timeout expires.
|
* @return zero on success, -EIO if timeout expires.
|
||||||
*/
|
*/
|
||||||
static int waitUntilReady(uint32_t timeout)
|
static int waitUntilReady(const struct W25QxCfg *cfg, uint32_t timeout)
|
||||||
{
|
{
|
||||||
// Each wait tick is 500us
|
// Each wait tick is 500us
|
||||||
timeout *= 2;
|
timeout *= 2;
|
||||||
|
@ -66,13 +58,15 @@ static int waitUntilReady(uint32_t timeout)
|
||||||
delayUs(500);
|
delayUs(500);
|
||||||
timeout--;
|
timeout--;
|
||||||
|
|
||||||
gpio_clearPin(FLASH_CS);
|
uint8_t cmd[] = {CMD_RDSTA, 0x00};
|
||||||
spiFlash_SendRecv(CMD_RDSTA);
|
uint8_t ret[2];
|
||||||
uint8_t status = spiFlash_SendRecv(0x00);
|
|
||||||
gpio_setPin(FLASH_CS);
|
gpioPin_clear(&cfg->cs);
|
||||||
|
spi_transfer(cfg->spi, cmd, ret, 2);
|
||||||
|
gpioPin_set(&cfg->cs);
|
||||||
|
|
||||||
/* If busy flag is low, we're done */
|
/* If busy flag is low, we're done */
|
||||||
if((status & 0x01) == 0)
|
if((ret[1] & 0x01) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,146 +74,162 @@ static int waitUntilReady(uint32_t timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void W25Qx_init()
|
void W25Qx_init(const struct nvmDevice *dev)
|
||||||
{
|
{
|
||||||
gpio_setMode(FLASH_CS, OUTPUT);
|
const struct W25QxCfg *cfg = (const struct W25QxCfg *) dev->priv;
|
||||||
gpio_setPin(FLASH_CS);
|
|
||||||
|
|
||||||
spiFlash_init();
|
gpioPin_setMode(&cfg->cs, OUTPUT);
|
||||||
W25Qx_wakeup();
|
gpioPin_set(&cfg->cs);
|
||||||
|
|
||||||
|
W25Qx_wakeup(dev);
|
||||||
// TODO: Implement sleep to increase power saving
|
// TODO: Implement sleep to increase power saving
|
||||||
}
|
}
|
||||||
|
|
||||||
void W25Qx_terminate()
|
void W25Qx_terminate(const struct nvmDevice *dev)
|
||||||
{
|
{
|
||||||
W25Qx_sleep();
|
const struct W25QxCfg *cfg = (const struct W25QxCfg *) dev->priv;
|
||||||
|
|
||||||
gpio_setMode(FLASH_CS, INPUT);
|
W25Qx_sleep(dev);
|
||||||
|
gpioPin_setMode(&cfg->cs, INPUT);
|
||||||
spiFlash_terminate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void W25Qx_wakeup()
|
void W25Qx_wakeup(const struct nvmDevice *dev)
|
||||||
{
|
{
|
||||||
gpio_clearPin(FLASH_CS);
|
const struct W25QxCfg *cfg = (const struct W25QxCfg *) dev->priv;
|
||||||
spiFlash_SendRecv(CMD_WKUP);
|
const uint8_t cmd = CMD_WKUP;
|
||||||
gpio_setPin(FLASH_CS);
|
|
||||||
|
spi_acquire(cfg->spi);
|
||||||
|
|
||||||
|
gpioPin_clear(&cfg->cs);
|
||||||
|
spi_send(cfg->spi, &cmd, 1);
|
||||||
|
gpioPin_set(&cfg->cs);
|
||||||
|
|
||||||
|
spi_release(cfg->spi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void W25Qx_sleep()
|
void W25Qx_sleep(const struct nvmDevice *dev)
|
||||||
{
|
{
|
||||||
gpio_clearPin(FLASH_CS);
|
const struct W25QxCfg *cfg = (const struct W25QxCfg *) dev->priv;
|
||||||
spiFlash_SendRecv(CMD_PDWN);
|
const uint8_t cmd = CMD_PDWN;
|
||||||
gpio_setPin(FLASH_CS);
|
|
||||||
|
spi_acquire(cfg->spi);
|
||||||
|
|
||||||
|
gpioPin_clear(&cfg->cs);
|
||||||
|
spi_send(cfg->spi, &cmd, 1);
|
||||||
|
gpioPin_set(&cfg->cs);
|
||||||
|
|
||||||
|
spi_release(cfg->spi);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t W25Qx_readSecurityRegister(uint32_t addr, void* buf, size_t len)
|
static int nvm_api_readSecReg(const struct nvmDevice *dev, uint32_t offset, void *data, size_t len)
|
||||||
{
|
{
|
||||||
uint32_t addrBase = addr & 0x3000;
|
const struct W25QxSecRegDevice *pDev = (const struct W25QxSecRegDevice *) dev;
|
||||||
uint32_t addrRange = addr & 0xCFFF;
|
const struct W25QxCfg *cfg = (const struct W25QxCfg *) dev->priv;
|
||||||
if((addrBase < 0x1000) || (addrBase > 0x3000)) return -1; /* Out of base */
|
|
||||||
if(addrRange > 0xFF) return -1; /* Out of range */
|
|
||||||
|
|
||||||
/* Keep 256-byte boundary to avoid wrap-around when reading */
|
// Keep 256-byte boundary to avoid wrap-around when reading
|
||||||
size_t readLen = len;
|
size_t readLen = len;
|
||||||
if((addrRange + len) > 0xFF)
|
if((offset + len) > 0xFF)
|
||||||
{
|
{
|
||||||
readLen = 0xFF - (addrRange & 0xFF);
|
readLen = 0xFF - (offset & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
gpio_clearPin(FLASH_CS);
|
uint32_t address = pDev->baseAddr + offset;
|
||||||
spiFlash_SendRecv(CMD_RSECR); /* Command */
|
const uint8_t command[] =
|
||||||
spiFlash_SendRecv((addr >> 16) & 0xFF); /* Address high */
|
|
||||||
spiFlash_SendRecv((addr >> 8) & 0xFF); /* Address middle */
|
|
||||||
spiFlash_SendRecv(addr & 0xFF); /* Address low */
|
|
||||||
spiFlash_SendRecv(0x00); /* Dummy byte */
|
|
||||||
|
|
||||||
for(size_t i = 0; i < readLen; i++)
|
|
||||||
{
|
{
|
||||||
((uint8_t *) buf)[i] = spiFlash_SendRecv(0x00);
|
CMD_RSECR, // Command
|
||||||
}
|
(address >> 16) & 0xFF, // Address high
|
||||||
|
(address >> 8) & 0xFF, // Address middle
|
||||||
|
address & 0xFF, // Address low
|
||||||
|
0x00 // Dummy byte
|
||||||
|
};
|
||||||
|
|
||||||
gpio_setPin(FLASH_CS);
|
spi_acquire(cfg->spi);
|
||||||
|
gpioPin_clear(&cfg->cs);
|
||||||
|
|
||||||
return ((ssize_t) readLen);
|
spi_send(cfg->spi, command, sizeof(command));
|
||||||
}
|
spi_receive(cfg->spi, data, readLen);
|
||||||
|
|
||||||
int W25Qx_readData(uint32_t addr, void* buf, size_t len)
|
gpioPin_set(&cfg->cs);
|
||||||
{
|
spi_release(cfg->spi);
|
||||||
gpio_clearPin(FLASH_CS);
|
|
||||||
spiFlash_SendRecv(CMD_READ); /* Command */
|
|
||||||
spiFlash_SendRecv((addr >> 16) & 0xFF); /* Address high */
|
|
||||||
spiFlash_SendRecv((addr >> 8) & 0xFF); /* Address middle */
|
|
||||||
spiFlash_SendRecv(addr & 0xFF); /* Address low */
|
|
||||||
|
|
||||||
for(size_t i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
((uint8_t *) buf)[i] = spiFlash_SendRecv(0x00);
|
|
||||||
}
|
|
||||||
|
|
||||||
gpio_setPin(FLASH_CS);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int W25Qx_erase(uint32_t addr, size_t size)
|
static int nvm_api_read(const struct nvmDevice *dev, uint32_t offset, void *data, size_t len)
|
||||||
{
|
{
|
||||||
|
const struct W25QxCfg *cfg = (const struct W25QxCfg *) dev->priv;
|
||||||
|
|
||||||
|
const uint8_t command[] =
|
||||||
|
{
|
||||||
|
CMD_READ, // Command
|
||||||
|
(offset >> 16) & 0xFF, // Address high
|
||||||
|
(offset >> 8) & 0xFF, // Address middle
|
||||||
|
offset & 0xFF, // Address low
|
||||||
|
};
|
||||||
|
|
||||||
|
spi_acquire(cfg->spi);
|
||||||
|
gpioPin_clear(&cfg->cs);
|
||||||
|
|
||||||
|
spi_send(cfg->spi, command, sizeof(command));
|
||||||
|
spi_receive(cfg->spi, data, len);
|
||||||
|
|
||||||
|
gpioPin_set(&cfg->cs);
|
||||||
|
spi_release(cfg->spi);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvm_api_erase(const struct nvmDevice *dev, uint32_t offset, size_t size)
|
||||||
|
{
|
||||||
|
const struct W25QxCfg *cfg = (const struct W25QxCfg *) dev->priv;
|
||||||
|
uint8_t command[4];
|
||||||
|
|
||||||
// Addr or size not aligned to sector size
|
// Addr or size not aligned to sector size
|
||||||
if(((addr % SECT_SIZE) != 0) || ((size % SECT_SIZE) != 0))
|
if(((offset % SECT_SIZE) != 0) || ((size % SECT_SIZE) != 0))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
gpio_clearPin(FLASH_CS);
|
spi_acquire(cfg->spi);
|
||||||
spiFlash_SendRecv(CMD_WREN); /* Write enable */
|
|
||||||
gpio_setPin(FLASH_CS);
|
|
||||||
|
|
||||||
delayUs(5);
|
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
while(size > 0)
|
while(size > 0)
|
||||||
{
|
{
|
||||||
gpio_clearPin(FLASH_CS);
|
// Write enable, has to be issued for each erase operation
|
||||||
spiFlash_SendRecv(CMD_ESECT); /* Command */
|
command[0] = CMD_WREN;
|
||||||
spiFlash_SendRecv((addr >> 16) & 0xFF); /* Address high */
|
gpioPin_clear(&cfg->cs);
|
||||||
spiFlash_SendRecv((addr >> 8) & 0xFF); /* Address middle */
|
spi_send(cfg->spi, command, 1);
|
||||||
spiFlash_SendRecv(addr & 0xFF); /* Address low */
|
gpioPin_set(&cfg->cs);
|
||||||
gpio_setPin(FLASH_CS);
|
|
||||||
|
|
||||||
ret = waitUntilReady(500);
|
delayUs(5);
|
||||||
|
|
||||||
|
// Sector erase
|
||||||
|
command[0] = CMD_ESECT; // Command
|
||||||
|
command[1] = (offset >> 16) & 0xFF; // Address high
|
||||||
|
command[2] = (offset >> 8) & 0xFF; // Address middle
|
||||||
|
command[3] = offset & 0xFF; // Address low
|
||||||
|
|
||||||
|
gpioPin_clear(&cfg->cs);
|
||||||
|
spi_send(cfg->spi, command, 4);
|
||||||
|
gpioPin_set(&cfg->cs);
|
||||||
|
|
||||||
|
ret = waitUntilReady(cfg, 500);
|
||||||
if(ret < 0)
|
if(ret < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
size -= SECT_SIZE;
|
size -= SECT_SIZE;
|
||||||
addr += SECT_SIZE;
|
offset += SECT_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spi_release(cfg->spi);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool W25Qx_eraseChip()
|
static ssize_t W25Qx_writePage(const struct nvmDevice *dev, uint32_t addr,
|
||||||
|
const void* buf, size_t len)
|
||||||
{
|
{
|
||||||
gpio_clearPin(FLASH_CS);
|
const struct W25QxCfg *cfg = (const struct W25QxCfg *) dev->priv;
|
||||||
spiFlash_SendRecv(CMD_WREN);
|
|
||||||
gpio_setPin(FLASH_CS);
|
|
||||||
|
|
||||||
delayUs(5);
|
// Keep page boundary to avoid wrap-around when writing
|
||||||
|
|
||||||
gpio_clearPin(FLASH_CS);
|
|
||||||
spiFlash_SendRecv(CMD_ECHIP);
|
|
||||||
gpio_setPin(FLASH_CS);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Wait until erase terminates, timeout after 200s.
|
|
||||||
*/
|
|
||||||
int ret = waitUntilReady(200000);
|
|
||||||
if(ret == 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t W25Qx_writePage(uint32_t addr, const void* buf, size_t len)
|
|
||||||
{
|
|
||||||
/* Keep page boundary to avoid wrap-around when writing */
|
|
||||||
size_t addrRange = addr & (PAGE_SIZE - 1);
|
size_t addrRange = addr & (PAGE_SIZE - 1);
|
||||||
size_t writeLen = len;
|
size_t writeLen = len;
|
||||||
if((addrRange + len) > PAGE_SIZE)
|
if((addrRange + len) > PAGE_SIZE)
|
||||||
|
@ -227,84 +237,55 @@ ssize_t W25Qx_writePage(uint32_t addr, const void* buf, size_t len)
|
||||||
writeLen = PAGE_SIZE - addrRange;
|
writeLen = PAGE_SIZE - addrRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpio_clearPin(FLASH_CS);
|
// Write enable bit has to be set before each page program
|
||||||
spiFlash_SendRecv(CMD_WREN); /* Write enable */
|
uint8_t command[4];
|
||||||
gpio_setPin(FLASH_CS);
|
command[0] = CMD_WREN;
|
||||||
|
|
||||||
delayUs(5);
|
spi_acquire(cfg->spi);
|
||||||
|
gpioPin_clear(&cfg->cs);
|
||||||
|
spi_send(cfg->spi, command, 1);
|
||||||
|
gpioPin_set(&cfg->cs);
|
||||||
|
|
||||||
gpio_clearPin(FLASH_CS);
|
// Page program
|
||||||
spiFlash_SendRecv(CMD_WRITE); /* Command */
|
command[0] = CMD_WRITE; // Command
|
||||||
spiFlash_SendRecv((addr >> 16) & 0xFF); /* Address high */
|
command[1] = (addr >> 16) & 0xFF; // Address high
|
||||||
spiFlash_SendRecv((addr >> 8) & 0xFF); /* Address middle */
|
command[2] = (addr >> 8) & 0xFF; // Address middle
|
||||||
spiFlash_SendRecv(addr & 0xFF); /* Address low */
|
command[3] = addr & 0xFF; // Address low
|
||||||
|
|
||||||
for(size_t i = 0; i < writeLen; i++)
|
gpioPin_clear(&cfg->cs);
|
||||||
{
|
spi_send(cfg->spi, command, 4);
|
||||||
uint8_t value = ((uint8_t *) buf)[i];
|
spi_send(cfg->spi, buf, writeLen);
|
||||||
(void) spiFlash_SendRecv(value);
|
gpioPin_set(&cfg->cs);
|
||||||
}
|
|
||||||
|
|
||||||
gpio_setPin(FLASH_CS);
|
// Wait until write terminates, timeout after 500ms.
|
||||||
|
int ret = waitUntilReady(cfg, 500);
|
||||||
|
spi_release(cfg->spi);
|
||||||
|
|
||||||
/*
|
|
||||||
* Wait until erase terminates, timeout after 500ms.
|
|
||||||
*/
|
|
||||||
int ret = waitUntilReady(500);
|
|
||||||
if(ret < 0)
|
if(ret < 0)
|
||||||
return (ssize_t) ret;
|
return (ssize_t) ret;
|
||||||
|
else
|
||||||
return writeLen;
|
return writeLen;
|
||||||
}
|
|
||||||
|
|
||||||
int W25Qx_writeData(uint32_t addr, const void *buf, size_t len)
|
|
||||||
{
|
|
||||||
while(len > 0)
|
|
||||||
{
|
|
||||||
size_t toWrite = len;
|
|
||||||
|
|
||||||
// Maximum single-shot write lenght is one page
|
|
||||||
if(toWrite >= PAGE_SIZE)
|
|
||||||
toWrite = PAGE_SIZE;
|
|
||||||
|
|
||||||
ssize_t written = W25Qx_writePage(addr, buf, toWrite);
|
|
||||||
if(written < 0)
|
|
||||||
return (int) written;
|
|
||||||
|
|
||||||
len -= (size_t) written;
|
|
||||||
buf = ((const uint8_t *) buf) + (size_t) written;
|
|
||||||
addr += (size_t) written;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nvm_api_readSecReg(const struct nvmDevice *dev, uint32_t offset, void *data, size_t len)
|
|
||||||
{
|
|
||||||
(void) dev;
|
|
||||||
|
|
||||||
return W25Qx_readSecurityRegister(offset, data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nvm_api_read(const struct nvmDevice *dev, uint32_t offset, void *data, size_t len)
|
|
||||||
{
|
|
||||||
(void) dev;
|
|
||||||
|
|
||||||
return W25Qx_readData(offset, data, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nvm_api_write(const struct nvmDevice *dev, uint32_t offset, const void *data, size_t len)
|
static int nvm_api_write(const struct nvmDevice *dev, uint32_t offset, const void *data, size_t len)
|
||||||
{
|
{
|
||||||
(void) dev;
|
while(len > 0)
|
||||||
|
{
|
||||||
|
// Maximum single-shot write length is one page
|
||||||
|
size_t toWrite = len;
|
||||||
|
if(toWrite >= PAGE_SIZE)
|
||||||
|
toWrite = PAGE_SIZE;
|
||||||
|
|
||||||
return W25Qx_writeData(offset, data, len);
|
ssize_t written = W25Qx_writePage(dev, offset, data, toWrite);
|
||||||
}
|
if(written < 0)
|
||||||
|
return (int) written;
|
||||||
|
|
||||||
static int nvm_api_erase(const struct nvmDevice *dev, uint32_t offset, size_t size)
|
len -= (size_t) written;
|
||||||
{
|
data = ((const uint8_t *) data) + (size_t) written;
|
||||||
(void) dev;
|
offset += (size_t) written;
|
||||||
|
}
|
||||||
|
|
||||||
return W25Qx_erase(offset, size);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct nvmOps W25Qx_ops =
|
const struct nvmOps W25Qx_ops =
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <peripherals/spi.h>
|
||||||
|
#include <peripherals/gpio.h>
|
||||||
#include <interfaces/nvmem.h>
|
#include <interfaces/nvmem.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,10 +33,19 @@
|
||||||
* volatile memory on various radios to store both calibration and contact data.
|
* volatile memory on various radios to store both calibration and contact data.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration data structure for W25Qx memory device.
|
||||||
|
*/
|
||||||
|
struct W25QxCfg
|
||||||
|
{
|
||||||
|
const struct spiDevice *spi;
|
||||||
|
const struct gpioPin cs;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Driver data structure for W25Qx security registers.
|
* Driver data structure for W25Qx security registers.
|
||||||
*/
|
*/
|
||||||
struct w25qSecRegDevice
|
struct W25QxSecRegDevice
|
||||||
{
|
{
|
||||||
const void *priv; ///< Device driver private data
|
const void *priv; ///< Device driver private data
|
||||||
const struct nvmOps *ops; ///< Device operations
|
const struct nvmOps *ops; ///< Device operations
|
||||||
|
@ -55,12 +66,13 @@ extern const struct nvmInfo W25Qx_info;
|
||||||
* @param name: device name.
|
* @param name: device name.
|
||||||
* @param sz: memory size, in bytes.
|
* @param sz: memory size, in bytes.
|
||||||
*/
|
*/
|
||||||
#define W25Qx_DEVICE_DEFINE(name, sz) \
|
#define W25Qx_DEVICE_DEFINE(name, config, sz) \
|
||||||
struct nvmDevice name = \
|
const struct nvmDevice name = \
|
||||||
{ \
|
{ \
|
||||||
.ops = &W25Qx_ops, \
|
.priv = &config, \
|
||||||
.info = &W25Qx_info, \
|
.ops = &W25Qx_ops, \
|
||||||
.size = sz \
|
.info = &W25Qx_info, \
|
||||||
|
.size = sz, \
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,24 +88,25 @@ extern const struct nvmInfo W25Qx_secReg_info;
|
||||||
* @param base: security register base address.
|
* @param base: security register base address.
|
||||||
* @param sz: memory size, in bytes.
|
* @param sz: memory size, in bytes.
|
||||||
*/
|
*/
|
||||||
#define W25Qx_SECREG_DEFINE(name, base, sz) \
|
#define W25Qx_SECREG_DEFINE(name, config, base, sz) \
|
||||||
struct w25qSecRegDevice name = \
|
const struct W25QxSecRegDevice name = \
|
||||||
{ \
|
{ \
|
||||||
.ops = &W25Qx_secReg_ops, \
|
.priv = &config, \
|
||||||
.info = &W25Qx_secReg_info, \
|
.ops = &W25Qx_secReg_ops, \
|
||||||
.size = sz, \
|
.info = &W25Qx_secReg_info, \
|
||||||
.baseAddr = base \
|
.size = sz, \
|
||||||
|
.baseAddr = base \
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise driver for external flash.
|
* Initialise driver for external flash.
|
||||||
*/
|
*/
|
||||||
void W25Qx_init();
|
void W25Qx_init(const struct nvmDevice *dev);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminate driver for external flash.
|
* Terminate driver for external flash.
|
||||||
*/
|
*/
|
||||||
void W25Qx_terminate();
|
void W25Qx_terminate(const struct nvmDevice *dev);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release flash chip from power down mode, this function should be called at
|
* Release flash chip from power down mode, this function should be called at
|
||||||
|
@ -102,76 +115,11 @@ void W25Qx_terminate();
|
||||||
* Application code must wait at least 3us before issuing any other command
|
* Application code must wait at least 3us before issuing any other command
|
||||||
* after this one.
|
* after this one.
|
||||||
*/
|
*/
|
||||||
void W25Qx_wakeup();
|
void W25Qx_wakeup(const struct nvmDevice *dev);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Put flash chip in low power mode.
|
* Put flash chip in low power mode.
|
||||||
*/
|
*/
|
||||||
void W25Qx_sleep();
|
void W25Qx_sleep(const struct nvmDevice *dev);
|
||||||
|
|
||||||
/**
|
|
||||||
* Read data from one of the flash security registers, located at addresses
|
|
||||||
* 0x1000, 0x2000 and 0x3000 and 256-byte wide.
|
|
||||||
* NOTE: If a read operation goes beyond the 256 byte boundary, length will be
|
|
||||||
* truncated to the one reaching the end of the register.
|
|
||||||
*
|
|
||||||
* @param addr: start address for read operation, must be the full register address.
|
|
||||||
* @param buf: pointer to a buffer where data is written to.
|
|
||||||
* @param len: number of bytes to read.
|
|
||||||
* @return: -1 if address is not whithin security registers address range, the
|
|
||||||
* number of bytes effectively read otherwise.
|
|
||||||
*/
|
|
||||||
ssize_t W25Qx_readSecurityRegister(uint32_t addr, void *buf, size_t len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read data from flash memory.
|
|
||||||
*
|
|
||||||
* @param addr: start address for read operation.
|
|
||||||
* @param buf: pointer to a buffer where data is written to.
|
|
||||||
* @param len: number of bytes to read.
|
|
||||||
* @return zero on success, negative errno code on fail.
|
|
||||||
*/
|
|
||||||
int W25Qx_readData(uint32_t addr, void *buf, size_t len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Erase a flash memory area.
|
|
||||||
* The start address and erase size must be aligned to page size. The function
|
|
||||||
* blocks until the erase process terminates.
|
|
||||||
*
|
|
||||||
* @param addr: start address.
|
|
||||||
* @param size: size of the area to be erased.
|
|
||||||
* @return zero on success, negative errno code on fail.
|
|
||||||
*/
|
|
||||||
int W25Qx_erase(uint32_t addr, size_t size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Full chip erase.
|
|
||||||
* Function returns when erase process terminated.
|
|
||||||
*
|
|
||||||
* @return true on success, false on failure.
|
|
||||||
*/
|
|
||||||
bool W25Qx_eraseChip();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write data to a 256-byte flash memory page.
|
|
||||||
* NOTE: if data size goes beyond the 256 byte boundary, length will be truncated
|
|
||||||
* to the one reaching the end of the page.
|
|
||||||
*
|
|
||||||
* @param addr: start address for write operation.
|
|
||||||
* @param buf: pointer to data buffer.
|
|
||||||
* @param len: number of bytes to written.
|
|
||||||
* @return: -1 on error, the number of bytes effectively written otherwise.
|
|
||||||
*/
|
|
||||||
ssize_t W25Qx_writePage(uint32_t addr, const void *buf, size_t len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write data to flash memory.
|
|
||||||
*
|
|
||||||
* @param addr: start address for read operation.
|
|
||||||
* @param buf: pointer to a buffer where data is written to.
|
|
||||||
* @param len: number of bytes to read.
|
|
||||||
* @return zero on success, negative errno code on fail.
|
|
||||||
*/
|
|
||||||
int W25Qx_writeData(uint32_t addr, const void *buf, size_t len);
|
|
||||||
|
|
||||||
#endif /* W25Qx_H */
|
#endif /* W25Qx_H */
|
||||||
|
|
Ładowanie…
Reference in New Issue