summaryrefslogtreecommitdiff
path: root/nuttx/drivers/mtd
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-06-27 15:35:35 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-06-27 15:35:35 +0000
commitc055288263c9c4558e2737378af91634e477a84d (patch)
tree87622b31e3c2d7e8d0e1821669d99779745631c5 /nuttx/drivers/mtd
parentc455dee2b9bf6a37956071f5b9a16f786ccc0f0a (diff)
downloadpx4-nuttx-c055288263c9c4558e2737378af91634e477a84d.tar.gz
px4-nuttx-c055288263c9c4558e2737378af91634e477a84d.tar.bz2
px4-nuttx-c055288263c9c4558e2737378af91634e477a84d.zip
The SST25 driver now works with SST25 (at least using the slow write mode)
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4875 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/drivers/mtd')
-rw-r--r--nuttx/drivers/mtd/sst25.c223
1 files changed, 147 insertions, 76 deletions
diff --git a/nuttx/drivers/mtd/sst25.c b/nuttx/drivers/mtd/sst25.c
index 83fbdc347..717a9c898 100644
--- a/nuttx/drivers/mtd/sst25.c
+++ b/nuttx/drivers/mtd/sst25.c
@@ -77,6 +77,17 @@
# define CONFIG_SST25_SPIFREQUENCY 20000000
#endif
+/* There is a bug in the current code when using the higher speed AAI write sequence.
+ * The nature of the bug is that the WRDI instruction is not working. At the end
+ * of the AAI sequence, the status register continues to report that the SST25 is
+ * write enabled (WEL bit) and in AAI mode (AAI bit). This *must* be fixed in any
+ * production code if you want to have proper write performance.
+ */
+
+#warning "REVISIT"
+#undef CONFIG_SST25_SLOWWRITE
+#define CONFIG_SST25_SLOWWRITE 1
+
/* SST25 Instructions ***************************************************************/
/* Command Value Description Addr Data */
/* Dummy */
@@ -150,7 +161,7 @@
# define SST25_SECTOR_SIZE 512 /* Sector size = 512 bytes */
#endif
-#define SST25_ERASE_STATE 0xff /* State of FLASH when erased */
+#define SST25_ERASED_STATE 0xff /* State of FLASH when erased */
/* Cache flags */
@@ -205,7 +216,7 @@ static inline int sst25_readid(FAR struct sst25_dev_s *priv);
#ifndef CONFIG_SST25_READONLY
static void sst25_unprotect(FAR struct spi_dev_s *dev);
#endif
-static void sst25_waitwritecomplete(FAR struct sst25_dev_s *priv);
+static uint8_t sst25_waitwritecomplete(FAR struct sst25_dev_s *priv);
static inline void sst25_wren(FAR struct sst25_dev_s *priv);
static inline void sst25_wrdi(FAR struct sst25_dev_s *priv);
static void sst25_sectorerase(FAR struct sst25_dev_s *priv, off_t offset);
@@ -214,17 +225,17 @@ static void sst25_byteread(FAR struct sst25_dev_s *priv, FAR uint8_t *buffer,
off_t address, size_t nbytes);
#ifndef CONFIG_SST25_READONLY
#ifdef CONFIG_SST25_SLOWWRITE
-static void sst32_bytewrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *buffer,
+static void sst25_bytewrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *buffer,
off_t address, size_t nbytes);
#else
-static void sst32_wordwrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *buffer,
+static void sst25_wordwrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *buffer,
off_t address, size_t nbytes);
#endif
#ifdef CONFIG_SST25_SECTOR512
static void sst25_cacheflush(struct sst25_dev_s *priv);
static FAR uint8_t *sst25_cacheread(struct sst25_dev_s *priv, off_t sector);
static void sst25_cacheerase(struct sst25_dev_s *priv, off_t sector);
-static void sst32_cachewrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *buffer,
+static void sst25_cachewrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *buffer,
off_t sector, size_t nsectors);
#endif
#endif
@@ -373,7 +384,7 @@ static void sst25_unprotect(FAR struct spi_dev_s *dev)
* Name: sst25_waitwritecomplete
************************************************************************************/
-static void sst25_waitwritecomplete(struct sst25_dev_s *priv)
+static uint8_t sst25_waitwritecomplete(struct sst25_dev_s *priv)
{
uint8_t status;
@@ -430,15 +441,19 @@ static void sst25_waitwritecomplete(struct sst25_dev_s *priv)
* other peripherals to access the SPI bus.
*/
+#if 0 /* Makes writes too slow */
if ((status & SST25_SR_BUSY) != 0)
{
sst25_unlock(priv->dev);
usleep(1000);
sst25_lock(priv->dev);
}
+#endif
}
while ((status & SST25_SR_BUSY) != 0);
#endif
+
+ return status;
}
/************************************************************************************
@@ -477,7 +492,6 @@ static inline void sst25_wrdi(struct sst25_dev_s *priv)
/* Deselect the FLASH */
SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- fvdbg("Enabled\n");
}
/************************************************************************************
@@ -492,7 +506,7 @@ static void sst25_sectorerase(struct sst25_dev_s *priv, off_t sector)
/* Wait for any preceding write or erase operation to complete. */
- sst25_waitwritecomplete(priv);
+ (void)sst25_waitwritecomplete(priv);
/* Send write enable instruction */
@@ -529,7 +543,7 @@ static inline int sst25_chiperase(struct sst25_dev_s *priv)
/* Wait for any preceding write or erase operation to complete. */
- sst25_waitwritecomplete(priv);
+ (void)sst25_waitwritecomplete(priv);
/* Send write enable instruction */
@@ -557,11 +571,14 @@ static inline int sst25_chiperase(struct sst25_dev_s *priv)
static void sst25_byteread(FAR struct sst25_dev_s *priv, FAR uint8_t *buffer,
off_t address, size_t nbytes)
{
+ uint8_t status;
+
fvdbg("address: %08lx nbytes: %d\n", (long)address, (int)nbytes);
/* Wait for any preceding write or erase operation to complete. */
- sst25_waitwritecomplete(priv);
+ status = sst25_waitwritecomplete(priv);
+ DEBUGASSERT((status & (SST25_SR_WEL|SST25_SR_BP_MASK|SST25_SR_AAI)) == 0);
/* Select this FLASH part */
@@ -597,13 +614,15 @@ static void sst25_byteread(FAR struct sst25_dev_s *priv, FAR uint8_t *buffer,
}
/************************************************************************************
- * Name: sst32_bytewrite
+ * Name: sst25_bytewrite
************************************************************************************/
#if defined(CONFIG_SST25_SLOWWRITE) && !defined(CONFIG_SST25_READONLY)
-static void sst32_bytewrite(struct sst25_dev_s *priv, FAR const uint8_t *buffer,
+static void sst25_bytewrite(struct sst25_dev_s *priv, FAR const uint8_t *buffer,
off_t address, size_t nbytes)
{
+ uint8_t status;
+
fvdbg("address: %08lx nwords: %d\n", (long)address, (int)nbytes);
DEBUGASSERT(priv && buffer);
@@ -611,35 +630,44 @@ static void sst32_bytewrite(struct sst25_dev_s *priv, FAR const uint8_t *buffer,
for (; nbytes > 0; nbytes--)
{
- /* Wait for any preceding write or erase operation to complete. */
+ /* Skip over bytes that are begin written to the erased state */
- sst25_waitwritecomplete(priv);
+ if (*buffer != SST25_ERASED_STATE)
+ {
+ /* Wait for any preceding write or erase operation to complete. */
- /* Enable write access to the FLASH */
+ status = sst25_waitwritecomplete(priv);
+ DEBUGASSERT((status & (SST25_SR_WEL|SST25_SR_BP_MASK|SST25_SR_AAI)) == 0);
- sst25_wren(priv);
+ /* Enable write access to the FLASH */
+
+ sst25_wren(priv);
- /* Select this FLASH part */
+ /* Select this FLASH part */
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
+ SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
- /* Send "Byte Program (BP)" command */
+ /* Send "Byte Program (BP)" command */
- (void)SPI_SEND(priv->dev, SST25_BP);
+ (void)SPI_SEND(priv->dev, SST25_BP);
- /* Send the byte address high byte first. */
+ /* Send the byte address high byte first. */
- (void)SPI_SEND(priv->dev, (address >> 16) & 0xff);
- (void)SPI_SEND(priv->dev, (address >> 8) & 0xff);
- (void)SPI_SEND(priv->dev, address & 0xff);
+ (void)SPI_SEND(priv->dev, (address >> 16) & 0xff);
+ (void)SPI_SEND(priv->dev, (address >> 8) & 0xff);
+ (void)SPI_SEND(priv->dev, address & 0xff);
- /* Then write the single byte */
+ /* Then write the single byte */
- (void)SPI_SEND(priv->dev, *buffer);
+ (void)SPI_SEND(priv->dev, *buffer);
- /* Deselect the FLASH and setup for the next pass through the loop */
+ /* Deselect the FLASH and setup for the next pass through the loop */
+
+ SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
+ }
+
+ /* Advance to the next byte */
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
buffer++;
address++;
}
@@ -647,80 +675,123 @@ static void sst32_bytewrite(struct sst25_dev_s *priv, FAR const uint8_t *buffer,
#endif
/************************************************************************************
- * Name: sst32_wordwrite
+ * Name: sst25_wordwrite
************************************************************************************/
#if !defined(CONFIG_SST25_SLOWWRITE) && !defined(CONFIG_SST25_READONLY)
-static void sst32_wordwrite(struct sst25_dev_s *priv, FAR const uint8_t *buffer,
+static void sst25_wordwrite(struct sst25_dev_s *priv, FAR const uint8_t *buffer,
off_t address, size_t nbytes)
{
size_t nwords = (nbytes + 1) >> 1;
+ uint8_t status;
fvdbg("address: %08lx nwords: %d\n", (long)address, (int)nwords);
DEBUGASSERT(priv && buffer);
- /* Wait for any preceding write or erase operation to complete. */
+ /* Loop until all of the bytes have been written */
- sst25_waitwritecomplete(priv);
+ while (nwords > 0)
+ {
+ /* Skip over any data that is being written to the erased state */
- /* Enable write access to the FLASH */
+ while (nwords > 0 &&
+ buffer[0] == SST25_ERASED_STATE &&
+ buffer[1] == SST25_ERASED_STATE)
+ {
+ /* Decrement the word count and advance the write position */
- sst25_wren(priv);
+ nwords--;
+ buffer += 2;
+ address += 2;
+ }
+
+ /* If there are no further non-erased bytes in the user buffer, then
+ * we are finished.
+ */
+
+ if (nwords <= 0)
+ {
+ return;
+ }
+
+ /* Wait for any preceding write or erase operation to complete. */
+
+ status = sst25_waitwritecomplete(priv);
+ DEBUGASSERT((status & (SST25_SR_WEL|SST25_SR_BP_MASK|SST25_SR_AAI)) == 0);
+
+ /* Enable write access to the FLASH */
+
+ sst25_wren(priv);
- /* Select this FLASH part */
+ /* Select this FLASH part */
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
+ SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
- /* Send "Auto Address Increment (AAI)" command */
+ /* Send "Auto Address Increment (AAI)" command */
- (void)SPI_SEND(priv->dev, SST25_AAI);
+ (void)SPI_SEND(priv->dev, SST25_AAI);
- /* Send the word address high byte first. */
+ /* Send the word address high byte first. */
- (void)SPI_SEND(priv->dev, (address >> 16) & 0xff);
- (void)SPI_SEND(priv->dev, (address >> 8) & 0xff);
- (void)SPI_SEND(priv->dev, address & 0xff);
+ (void)SPI_SEND(priv->dev, (address >> 16) & 0xff);
+ (void)SPI_SEND(priv->dev, (address >> 8) & 0xff);
+ (void)SPI_SEND(priv->dev, address & 0xff);
- /* Then write one 16-bit word */
+ /* Then write one 16-bit word */
- SPI_SNDBLOCK(priv->dev, buffer, 2);
+ SPI_SNDBLOCK(priv->dev, buffer, 2);
- /* Deselect the FLASH: Chip Select high */
+ /* Deselect the FLASH: Chip Select high */
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- buffer += 2;
+ SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- /* Now loop, writing 16-bits of data on each pass through the loop until all
- * of the words have been transferred.
- */
+ /* Decrement the word count and advance the write position */
- for (nwords--; nwords > 0; nwords--)
- {
- /* Wait for the preceding write to complete. */
+ nwords--;
+ buffer += 2;
+ address += 2;
- sst25_waitwritecomplete(priv);
+ /* Now loop, writing 16-bits of data on each pass through the loop
+ * until all of the words have been transferred or until we encounter
+ * data to be written to the erased state.
+ */
- /* Select this FLASH part */
+ while (nwords > 0 &&
+ (buffer[0] != SST25_ERASED_STATE ||
+ buffer[1] != SST25_ERASED_STATE))
+ {
+ /* Wait for the preceding write to complete. */
- SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
+ status = sst25_waitwritecomplete(priv);
+ DEBUGASSERT((status & (SST25_SR_WEL|SST25_SR_BP_MASK|SST25_SR_AAI)) == (SST25_SR_WEL|SST25_SR_AAI));
- /* Send "Auto Address Increment (AAI)" command with no address */
+ /* Select this FLASH part */
- (void)SPI_SEND(priv->dev, SST25_AAI);
+ SPI_SELECT(priv->dev, SPIDEV_FLASH, true);
- /* Then write one 16-bit word */
+ /* Send "Auto Address Increment (AAI)" command with no address */
- SPI_SNDBLOCK(priv->dev, buffer, 2);
- buffer += 2;
+ (void)SPI_SEND(priv->dev, SST25_AAI);
- /* Deselect the FLASH: Chip Select high */
+ /* Then write one 16-bit word */
- SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- }
+ SPI_SNDBLOCK(priv->dev, buffer, 2);
+
+ /* Deselect the FLASH: Chip Select high */
+
+ SPI_SELECT(priv->dev, SPIDEV_FLASH, false);
- /* Disable writing */
+ /* Decrement the word count and advance the write position */
+
+ nwords--;
+ buffer += 2;
+ address += 2;
+ }
- sst25_wrdi(priv);
+ /* Disable writing */
+
+ sst25_wrdi(priv);
+ }
}
#endif
@@ -741,10 +812,10 @@ static void sst25_cacheflush(struct sst25_dev_s *priv)
/* Write entire erase block to FLASH */
#ifdef CONFIG_SST25_SLOWWRITE
- sst32_bytewrite(priv, priv->sector, (off_t)priv->esectno << priv->sectorshift,
+ sst25_bytewrite(priv, priv->sector, (off_t)priv->esectno << priv->sectorshift,
(1 << priv->sectorshift));
#else
- sst32_wordwrite(priv, priv->sector, (off_t)priv->esectno << priv->sectorshift,
+ sst25_wordwrite(priv, priv->sector, (off_t)priv->esectno << priv->sectorshift,
(1 << priv->sectorshift));
#endif
@@ -841,7 +912,7 @@ static void sst25_cacheerase(struct sst25_dev_s *priv, off_t sector)
* time).
*/
- memset(dest, SST25_ERASE_STATE, SST25_SECTOR_SIZE);
+ memset(dest, SST25_ERASED_STATE, SST25_SECTOR_SIZE);
SET_DIRTY(priv);
}
#endif
@@ -851,7 +922,7 @@ static void sst25_cacheerase(struct sst25_dev_s *priv, off_t sector)
************************************************************************************/
#if defined(CONFIG_SST25_SECTOR512) && !defined(CONFIG_SST25_READONLY)
-static void sst32_cachewrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *buffer,
+static void sst25_cachewrite(FAR struct sst25_dev_s *priv, FAR const uint8_t *buffer,
off_t sector, size_t nsectors)
{
FAR uint8_t *dest;
@@ -941,7 +1012,7 @@ static int sst25_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nbloc
************************************************************************************/
static ssize_t sst25_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR uint8_t *buffer)
+ FAR uint8_t *buffer)
{
#ifdef CONFIG_SST25_SECTOR512
ssize_t nbytes;
@@ -980,7 +1051,7 @@ static ssize_t sst25_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t n
************************************************************************************/
static ssize_t sst25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks,
- FAR const uint8_t *buffer)
+ FAR const uint8_t *buffer)
{
#ifdef CONFIG_SST25_READONLY
return -EACCESS;
@@ -994,12 +1065,12 @@ static ssize_t sst25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t
sst25_lock(priv->dev);
#if defined(CONFIG_SST25_SECTOR512)
- sst32_cachewrite(priv, buffer, startblock, nblocks);
+ sst25_cachewrite(priv, buffer, startblock, nblocks);
#elif defined(CONFIG_SST25_SLOWWRITE)
- sst32_bytewrite(priv, buffer, startblock << priv->sectorshift,
+ sst25_bytewrite(priv, buffer, startblock << priv->sectorshift,
nblocks << priv->sectorshift);
#else
- sst32_wordwrite(priv, buffer, startblock << priv->sectorshift,
+ sst25_wordwrite(priv, buffer, startblock << priv->sectorshift,
nblocks << priv->sectorshift);
#endif
sst25_unlock(priv->dev);
@@ -1013,7 +1084,7 @@ static ssize_t sst25_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t
************************************************************************************/
static ssize_t sst25_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
- FAR uint8_t *buffer)
+ FAR uint8_t *buffer)
{
FAR struct sst25_dev_s *priv = (FAR struct sst25_dev_s *)dev;