summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nuttx/Documentation/NuttxPortingGuide.html1
-rw-r--r--nuttx/TODO24
-rwxr-xr-xnuttx/arch/arm/src/imx/imx_spi.c1
-rwxr-xr-xnuttx/arch/arm/src/lm3s/lm3s_ssi.c1
-rwxr-xr-xnuttx/arch/arm/src/stm32/stm32_internal.h17
-rwxr-xr-xnuttx/arch/arm/src/stm32/stm32_spi.c284
-rwxr-xr-xnuttx/arch/z80/src/ez80/ez80_spi.c2
-rw-r--r--nuttx/configs/mcu123-lpc214x/src/up_spi.c2
-rw-r--r--nuttx/configs/olimex-strp711/src/up_spi.c2
-rwxr-xr-xnuttx/configs/stm3210e-eval/src/stm3210e-internal.h5
-rwxr-xr-xnuttx/configs/stm3210e-eval/src/up_nsh.c73
-rwxr-xr-xnuttx/configs/stm3210e-eval/src/up_spi.c47
-rw-r--r--nuttx/drivers/mtd/m25px.c124
-rw-r--r--nuttx/include/nuttx/spi.h24
14 files changed, 333 insertions, 274 deletions
diff --git a/nuttx/Documentation/NuttxPortingGuide.html b/nuttx/Documentation/NuttxPortingGuide.html
index a9bf7df8d..dec31beea 100644
--- a/nuttx/Documentation/NuttxPortingGuide.html
+++ b/nuttx/Documentation/NuttxPortingGuide.html
@@ -1805,6 +1805,7 @@ extern void up_ledoff(int led);
Each SPI device driver must implement an instance of <code>struct spi_ops_s</code>.
That structure defines a call table with the following methods:
<ul>
+ <p><code>void lock(FAR struct spi_dev_s *dev);</code></p>
<p><code>void select(FAR struct spi_dev_s *dev, enum spi_dev_e devid, boolean selected);</code><br>
<code>uint32 setfrequency(FAR struct spi_dev_s *dev, uint32 frequency);</code><br>
<code>void setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode);</code><br>
diff --git a/nuttx/TODO b/nuttx/TODO
index 83c451eb0..c5e4aa36c 100644
--- a/nuttx/TODO
+++ b/nuttx/TODO
@@ -26,6 +26,7 @@ NuttX TODO List (Last updated September 16, 2009)
(8) ARM/LPC214x (arch/arm/src/lpc214x/)
(3) ARM/STR71x (arch/arm/src/str71x/)
(3) ARM/LM3S6918 (arch/arm/src/lm3s/)
+ (5) ARM/STM32 (arch/arm/src/stm32/)
(4) pjrc-8052 / MCS51 (arch/pjrc-8051/)
(2) Hitachi/Renesas SH-1 (arch/sh/src/sh1)
(4) Renesas M16C/26 (arch/sh/src/m16c)
@@ -641,6 +642,29 @@ o ARM/LM3S6918 (arch/arm/src/lm3s/)
Status: Open
Priority: Low -- unless some dependency-related build issues is discovered.
+o ARM/STM32 (arch/arm/src/stm32/)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Description: DMA subsystem is untested.
+ Status: Open
+ Priority: Low -- for now
+
+ Description: NOR Flash driver and FTL layer to support a file system.
+ Status: Open
+ Priority: Low
+
+ Description: MMC/SD SDIO driver needed.
+ Status: Open
+ Priority: Medium
+
+ Description USB device-side driver
+ Status: Open
+ Priority: Medium-High
+
+ Description: Framebuffer driver needed.
+ Status: Open
+ Priority: High
+
o pjrc-8052 / MCS51 (arch/pjrc-8051/)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/nuttx/arch/arm/src/imx/imx_spi.c b/nuttx/arch/arm/src/imx/imx_spi.c
index f1b3262a0..46cfb6913 100755
--- a/nuttx/arch/arm/src/imx/imx_spi.c
+++ b/nuttx/arch/arm/src/imx/imx_spi.c
@@ -184,6 +184,7 @@ static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t
static const struct spi_ops_s g_spiops =
{
+ .lock = 0, /* Not yet implemented */
.select = imx_spiselect, /* Provided externally by board logic */
.setfrequency = spi_setfrequency,
.setmode = spi_setmode,
diff --git a/nuttx/arch/arm/src/lm3s/lm3s_ssi.c b/nuttx/arch/arm/src/lm3s/lm3s_ssi.c
index 65b01b625..2821dc87e 100755
--- a/nuttx/arch/arm/src/lm3s/lm3s_ssi.c
+++ b/nuttx/arch/arm/src/lm3s/lm3s_ssi.c
@@ -251,6 +251,7 @@ static void ssi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t
static const struct spi_ops_s g_spiops =
{
+ .lock = 0, /* Not yet implemented */
.select = lm3s_spiselect, /* Provided externally by board logic */
.setfrequency = ssi_setfrequency,
.setmode = ssi_setmode,
diff --git a/nuttx/arch/arm/src/stm32/stm32_internal.h b/nuttx/arch/arm/src/stm32/stm32_internal.h
index e5d429be7..58be75b61 100755
--- a/nuttx/arch/arm/src/stm32/stm32_internal.h
+++ b/nuttx/arch/arm/src/stm32/stm32_internal.h
@@ -610,9 +610,6 @@ EXTERN int stm32_ethinitialize(int intf);
* 2. Provide stm32_spi1/2/3select() and stm32_spi1/2/3status() functions in your
* board-specific logic. These functions will perform chip selection and
* status operations using GPIOs in the way your board is configured.
- * The select() methods must call stm32_spitake() when the chip is selected
- * and stm32_spigive() when the chip is deselected. This assures mutually
- * exclusive access to the SPI for the duration while a chip is selected.
* 3. Add a calls to up_spiinitialize() in your low level application
* initialization logic
* 4. The handle returned by up_spiinitialize() may then be used to bind the
@@ -631,20 +628,6 @@ EXTERN ubyte stm32_spi2status(FAR struct spi_dev_s *dev, enum spi_dev_e devid);
EXTERN void stm32_spi3select(FAR struct spi_dev_s *dev, enum spi_dev_e devid, boolean selected);
EXTERN ubyte stm32_spi3status(FAR struct spi_dev_s *dev, enum spi_dev_e devid);
-/************************************************************************************
- * Name: stm32_spitake() and stm32_spigive()
- *
- * Description:
- * The stm32_spi1/2/3select() and stm32_spi1/2/3status() methods must call
- * stm32_spitake() when the chip is selected and stm32_spigive() when the chip is
- * deselected. This assures mutually exclusive access to the SPI for the duration
- * while a chip is selected.
- *
- ************************************************************************************/
-
-EXTERN void stm32_spitake(FAR struct spi_dev_s *dev);
-EXTERN void stm32_spigive(FAR struct spi_dev_s *dev);
-
#undef EXTERN
#if defined(__cplusplus)
}
diff --git a/nuttx/arch/arm/src/stm32/stm32_spi.c b/nuttx/arch/arm/src/stm32/stm32_spi.c
index abd9538bb..2ca8989c8 100755
--- a/nuttx/arch/arm/src/stm32/stm32_spi.c
+++ b/nuttx/arch/arm/src/stm32/stm32_spi.c
@@ -46,9 +46,6 @@
* 2. Provide stm32_spi1/2/3select() and stm32_spi1/2/3status() functions in your
* board-specific logic. These functions will perform chip selection and
* status operations using GPIOs in the way your board is configured.
- * The select() methods must call stm32_spitake() when the chip is selected
- * and stm32_spigive() when the chip is deselected. This assures mutually
- * exclusive access to the SPI for the duration while a chip is selected.
* 3. Add a calls to up_spiinitialize() in your low level application
* initialization logic
* 4. The handle returned by up_spiinitialize() may then be used to bind the
@@ -119,6 +116,10 @@ struct stm32_spidev_s
struct spi_dev_s spidev; /* Externally visible part of the SPI interface */
uint32 spibase; /* SPIn base address */
uint32 spiclock; /* Clocking for the SPI module */
+ uint32 frequency; /* Requested clock frequency */
+ uint32 actual; /* Actual clock frequency */
+ ubyte nbits; /* Width of work in bits (8 or 16) */
+ ubyte mode; /* Mode 0,1,2,3 */
#ifdef CONFIG_STM32_SPI_INTERRUPTS
ubyte spiirq; /* SPI IRQ number */
#endif
@@ -167,6 +168,7 @@ static inline void spi_dmatxstart(FAR struct stm32_spidev_s *priv);
/* SPI methods */
+static int spi_lock(FAR struct spi_dev_s *dev, boolean lock);
static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency);
static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode);
static void spi_setbits(FAR struct spi_dev_s *dev, int nbits);
@@ -191,6 +193,7 @@ static void spi_portinitialize(FAR struct stm32_spidev_s *priv);
#ifdef CONFIG_STM32_SPI1
static const struct spi_ops_s g_sp1iops =
{
+ .lock = spi_lock,
.select = stm32_spi1select,
.setfrequency = spi_setfrequency,
.setmode = spi_setmode,
@@ -224,6 +227,7 @@ static struct stm32_spidev_s g_spi1dev =
#ifdef CONFIG_STM32_SPI2
static const struct spi_ops_s g_sp2iops =
{
+ .lock = spi_lock,
.select = stm32_spi2select,
.setfrequency = spi_setfrequency,
.setmode = spi_setmode,
@@ -257,6 +261,7 @@ static struct stm32_spidev_s g_spi2dev =
#ifdef CONFIG_STM32_SPI3
static const struct spi_ops_s g_sp3iops =
{
+ .lock = spi_lock,
.select = stm32_spi3select,
.setfrequency = spi_setfrequency,
.setmode = spi_setmode,
@@ -664,6 +669,51 @@ static void spi_modifycr1(FAR struct stm32_spidev_s *priv, uint16 setbits, uint1
spi_putreg(priv, STM32_SPI_CR1_OFFSET, cr1);
}
+/****************************************************************************
+ * Name: spi_lock
+ *
+ * Description:
+ * On SPI busses where there are multiple devices, it will be necessary to
+ * lock SPI to have exclusive access to the busses for a sequence of
+ * transfers. The bus should be locked before the chip is selected. After
+ * locking the SPI bus, the caller should then also call the setfrequency,
+ * setbits, and setmode methods to make sure that the SPI is properly
+ * configured for the device. If the SPI buss is being shared, then it
+ * may have been left in an incompatible state.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * lock - TRUE: Lock spi bus, FALSE: unlock SPI bus
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static int spi_lock(FAR struct spi_dev_s *dev, boolean lock)
+{
+ FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)dev;
+
+ if (lock)
+ {
+ /* Take the semaphore (perhaps waiting) */
+
+ while (sem_wait(&priv->exclsem) != 0)
+ {
+ /* The only case that an error should occur here is if the wait was awakened
+ * by a signal.
+ */
+
+ ASSERT(errno == EINTR);
+ }
+ }
+ else
+ {
+ (void)sem_post(&priv->exclsem);
+ }
+ return OK;
+}
+
/************************************************************************************
* Name: spi_setfrequency
*
@@ -685,67 +735,74 @@ static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency)
uint16 setbits;
uint32 actual;
- /* Choices are limited by PCLK frequency with a set of divisors */
+ /* Has the frequency changed? */
- if (frequency >= priv->spiclock >> 1)
+ if (frequency != priv->frequency)
{
- /* More than fPCLK/2. This is as fast as we can go */
+ /* Choices are limited by PCLK frequency with a set of divisors */
- setbits = SPI_CR1_FPCLCKd2; /* 000: fPCLK/2 */
- actual = priv->spiclock >> 1;
- }
- else if (frequency >= priv->spiclock >> 2)
- {
- /* Between fPCLCK/2 and fPCLCK/4, pick the slower */
+ if (frequency >= priv->spiclock >> 1)
+ {
+ /* More than fPCLK/2. This is as fast as we can go */
- setbits = SPI_CR1_FPCLCKd4; /* 001: fPCLK/4 */
- actual = priv->spiclock >> 2;
- }
- else if (frequency >= priv->spiclock >> 3)
- {
- /* Between fPCLCK/4 and fPCLCK/8, pick the slower */
+ setbits = SPI_CR1_FPCLCKd2; /* 000: fPCLK/2 */
+ actual = priv->spiclock >> 1;
+ }
+ else if (frequency >= priv->spiclock >> 2)
+ {
+ /* Between fPCLCK/2 and fPCLCK/4, pick the slower */
- setbits = SPI_CR1_FPCLCKd8; /* 010: fPCLK/8 */
- actual = priv->spiclock >> 3;
- }
- else if (frequency >= priv->spiclock >> 4)
- {
- /* Between fPCLCK/8 and fPCLCK/16, pick the slower */
+ setbits = SPI_CR1_FPCLCKd4; /* 001: fPCLK/4 */
+ actual = priv->spiclock >> 2;
+ }
+ else if (frequency >= priv->spiclock >> 3)
+ {
+ /* Between fPCLCK/4 and fPCLCK/8, pick the slower */
- setbits = SPI_CR1_FPCLCKd16; /* 011: fPCLK/16 */
- actual = priv->spiclock >> 4;
- }
- else if (frequency >= priv->spiclock >> 5)
- {
- /* Between fPCLCK/16 and fPCLCK/32, pick the slower */
+ setbits = SPI_CR1_FPCLCKd8; /* 010: fPCLK/8 */
+ actual = priv->spiclock >> 3;
+ }
+ else if (frequency >= priv->spiclock >> 4)
+ {
+ /* Between fPCLCK/8 and fPCLCK/16, pick the slower */
- setbits = SPI_CR1_FPCLCKd32; /* 100: fPCLK/32 */
- actual = priv->spiclock >> 5;
- }
- else if (frequency >= priv->spiclock >> 6)
- {
- /* Between fPCLCK/32 and fPCLCK/64, pick the slower */
+ setbits = SPI_CR1_FPCLCKd16; /* 011: fPCLK/16 */
+ actual = priv->spiclock >> 4;
+ }
+ else if (frequency >= priv->spiclock >> 5)
+ {
+ /* Between fPCLCK/16 and fPCLCK/32, pick the slower */
- setbits = SPI_CR1_FPCLCKd64; /* 101: fPCLK/64 */
- actual = priv->spiclock >> 6;
- }
- else if (frequency >= priv->spiclock >> 7)
- {
- /* Between fPCLCK/64 and fPCLCK/128, pick the slower */
+ setbits = SPI_CR1_FPCLCKd32; /* 100: fPCLK/32 */
+ actual = priv->spiclock >> 5;
+ }
+ else if (frequency >= priv->spiclock >> 6)
+ {
+ /* Between fPCLCK/32 and fPCLCK/64, pick the slower */
- setbits = SPI_CR1_FPCLCKd128; /* 110: fPCLK/128 */
- actual = priv->spiclock >> 7;
- }
- else
- {
- /* Less than fPCLK/128. This is as slow as we can go */
+ setbits = SPI_CR1_FPCLCKd64; /* 101: fPCLK/64 */
+ actual = priv->spiclock >> 6;
+ }
+ else if (frequency >= priv->spiclock >> 7)
+ {
+ /* Between fPCLCK/64 and fPCLCK/128, pick the slower */
+
+ setbits = SPI_CR1_FPCLCKd128; /* 110: fPCLK/128 */
+ actual = priv->spiclock >> 7;
+ }
+ else
+ {
+ /* Less than fPCLK/128. This is as slow as we can go */
- setbits = SPI_CR1_FPCLCKd256; /* 111: fPCLK/256 */
- actual = priv->spiclock >> 8;
- }
+ setbits = SPI_CR1_FPCLCKd256; /* 111: fPCLK/256 */
+ actual = priv->spiclock >> 8;
+ }
- spi_modifycr1(priv, setbits, SPI_CR1_BR_MASK);
- return actual;
+ spi_modifycr1(priv, setbits, SPI_CR1_BR_MASK);
+ priv->frequency = frequency;
+ priv->actual = actual;
+ }
+ return priv->actual;
}
/************************************************************************************
@@ -769,33 +826,41 @@ static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode)
uint16 setbits;
uint16 clrbits;
- switch (mode)
+ /* Has the mode changed? */
+
+ if (mode != priv->mode)
{
- case SPIDEV_MODE0: /* CPOL=0; CPHA=0 */
- setbits = 0;
- clrbits = SPI_CR1_CPOL|SPI_CR1_CPHA;
- break;
+ /* Yes... Set CR1 appropriately */
+
+ switch (mode)
+ {
+ case SPIDEV_MODE0: /* CPOL=0; CPHA=0 */
+ setbits = 0;
+ clrbits = SPI_CR1_CPOL|SPI_CR1_CPHA;
+ break;
- case SPIDEV_MODE1: /* CPOL=0; CPHA=1 */
- setbits = SPI_CR1_CPHA;
- clrbits = SPI_CR1_CPOL;
- break;
+ case SPIDEV_MODE1: /* CPOL=0; CPHA=1 */
+ setbits = SPI_CR1_CPHA;
+ clrbits = SPI_CR1_CPOL;
+ break;
- case SPIDEV_MODE2: /* CPOL=1; CPHA=0 */
- setbits = SPI_CR1_CPOL;
- clrbits = SPI_CR1_CPHA;
- break;
+ case SPIDEV_MODE2: /* CPOL=1; CPHA=0 */
+ setbits = SPI_CR1_CPOL;
+ clrbits = SPI_CR1_CPHA;
+ break;
- case SPIDEV_MODE3: /* CPOL=1; CPHA=1 */
- setbits = SPI_CR1_CPOL|SPI_CR1_CPHA;
- clrbits = 0;
- break;
+ case SPIDEV_MODE3: /* CPOL=1; CPHA=1 */
+ setbits = SPI_CR1_CPOL|SPI_CR1_CPHA;
+ clrbits = 0;
+ break;
- default:
- return;
- }
+ default:
+ return;
+ }
- spi_modifycr1(priv, setbits, clrbits);
+ spi_modifycr1(priv, setbits, clrbits);
+ priv->mode = mode;
+ }
}
/************************************************************************************
@@ -819,23 +884,31 @@ static void spi_setbits(FAR struct spi_dev_s *dev, int nbits)
uint16 setbits;
uint16 clrbits;
- switch (nbits)
+ /* Has the number of bits changed? */
+
+ if (nbits != priv->nbits)
{
- case 8:
- setbits = 0;
- clrbits = SPI_CR1_DFF;
- break;
+ /* Yes... Set CR1 appropriately */
+
+ switch (nbits)
+ {
+ case 8:
+ setbits = 0;
+ clrbits = SPI_CR1_DFF;
+ break;
- case 16:
- setbits = SPI_CR1_DFF;
- clrbits = 0;
- break;
+ case 16:
+ setbits = SPI_CR1_DFF;
+ clrbits = 0;
+ break;
- default:
- return;
- }
+ default:
+ return;
+ }
- spi_modifycr1(priv, setbits, clrbits);
+ spi_modifycr1(priv, setbits, clrbits);
+ priv->nbits = nbits;
+ }
}
/************************************************************************************
@@ -1094,8 +1167,12 @@ static void spi_portinitialize(FAR struct stm32_spidev_s *priv)
setbits = SPI_CR1_MSTR|SPI_CR1_SSI|SPI_CR1_SSM;
spi_modifycr1(priv, setbits, clrbits);
+ priv->nbits = 8;
+ priv->mode = SPIDEV_MODE0;
+
/* Select a default frequency of approx. 400KHz */
+ priv->frequency = 0;
spi_setfrequency((FAR struct spi_dev_s *)priv, 400000);
/* CRCPOLY configuration */
@@ -1227,37 +1304,4 @@ FAR struct spi_dev_s *up_spiinitialize(int port)
return (FAR struct spi_dev_s *)priv;
}
-/************************************************************************************
- * Name: stm32_spitake() and stm32_spigive()
- *
- * Description:
- * The stm32_spi1/2/3select() and stm32_spi1/2/3status() methods must call
- * stm32_spitake() when the chip is selected and stm32_spigive() when the chip is
- * deselected. This assures mutually exclusive access to the SPI for the duration
- * while a chip is selected.
- *
- ************************************************************************************/
-
-void stm32_spitake(FAR struct spi_dev_s *dev)
-{
- FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)dev;
-
- /* Take the semaphore (perhaps waiting) */
-
- while (sem_wait(&priv->exclsem) != 0)
- {
- /* The only case that an error should occur here is if the wait was awakened
- * by a signal.
- */
-
- ASSERT(errno == EINTR);
- }
-}
-
-void stm32_spigive(FAR struct spi_dev_s *dev)
-{
- FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)dev;
- (void)sem_post(&priv->exclsem);
-}
-
#endif /* CONFIG_STM32_SPI1 || CONFIG_STM32_SPI2 || CONFIG_STM32_SPI3 */
diff --git a/nuttx/arch/z80/src/ez80/ez80_spi.c b/nuttx/arch/z80/src/ez80/ez80_spi.c
index 8e34de10e..d051f074f 100755
--- a/nuttx/arch/z80/src/ez80/ez80_spi.c
+++ b/nuttx/arch/z80/src/ez80/ez80_spi.c
@@ -77,6 +77,7 @@ static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t
static const struct spi_ops_s g_spiops =
{
+ 0, /* lock() method not yet implemented */
ez80_spiselect, /* Provided externally by board logic */
spi_setfrequency,
spi_setmode,
@@ -85,6 +86,7 @@ static const struct spi_ops_s g_spiops =
spi_send,
spi_sndblock,
spi_recvblock,
+ 0 /* registercallback not yet implemented */
};
/* This supports is only a single SPI bus/port. If you port this to an
diff --git a/nuttx/configs/mcu123-lpc214x/src/up_spi.c b/nuttx/configs/mcu123-lpc214x/src/up_spi.c
index c8cd831ba..50d41cc90 100644
--- a/nuttx/configs/mcu123-lpc214x/src/up_spi.c
+++ b/nuttx/configs/mcu123-lpc214x/src/up_spi.c
@@ -133,12 +133,14 @@ static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t
static const struct spi_ops_s g_spiops =
{
+ .lock = 0, /* Not yet implemented */
.select = spi_select,
.setfrequency = spi_setfrequency,
.status = spi_status,
.send = spi_send,
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
+ .registercallback = 0, /* Not implemented */
};
static struct spi_dev_s g_spidev = { &g_spiops };
diff --git a/nuttx/configs/olimex-strp711/src/up_spi.c b/nuttx/configs/olimex-strp711/src/up_spi.c
index dc520449d..04337445b 100644
--- a/nuttx/configs/olimex-strp711/src/up_spi.c
+++ b/nuttx/configs/olimex-strp711/src/up_spi.c
@@ -276,12 +276,14 @@ static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t
static const struct spi_ops_s g_spiops =
{
+ .lock = 0, /* Not yet implemented */
.select = spi_select,
.setfrequency = spi_setfrequency,
.status = spi_status,
.send = spi_send,
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
+ .registercallback = 0, /* Not implemented */
};
#ifdef CONFIG_STR71X_BSPI0
diff --git a/nuttx/configs/stm3210e-eval/src/stm3210e-internal.h b/nuttx/configs/stm3210e-eval/src/stm3210e-internal.h
index 7d9f20e74..186769575 100755
--- a/nuttx/configs/stm3210e-eval/src/stm3210e-internal.h
+++ b/nuttx/configs/stm3210e-eval/src/stm3210e-internal.h
@@ -70,11 +70,6 @@
#define GPIO_LED3 (GPIO_OUTPUT|GPIO_CNF_OUTPP|GPIO_MODE_50MHz|GPIO_OUTPUT_CLEAR|GPIO_PORTF|GPIO_PIN8)
#define GPIO_LED4 (GPIO_OUTPUT|GPIO_CNF_OUTPP|GPIO_MODE_50MHz|GPIO_OUTPUT_CLEAR|GPIO_PORTF|GPIO_PIN9)
-/* MMC/SD SPI1 chip select: PC.12 */
-
-#warning "MicoSD is on SDIO port, not SPI"
-#define GPIO_MMCSD_CS (GPIO_OUTPUT|GPIO_CNF_OUTPP|GPIO_MODE_50MHz|GPIO_OUTPUT_SET|GPIO_PORTC|GPIO_PIN12)
-
/* SPI FLASH chip select: PA.4 */
#define GPIO_FLASH_CS (GPIO_OUTPUT|GPIO_CNF_OUTPP|GPIO_MODE_50MHz|GPIO_OUTPUT_SET|GPIO_PORTB|GPIO_PIN2)
diff --git a/nuttx/configs/stm3210e-eval/src/up_nsh.c b/nuttx/configs/stm3210e-eval/src/up_nsh.c
index 5ce767b45..01dcb440b 100755
--- a/nuttx/configs/stm3210e-eval/src/up_nsh.c
+++ b/nuttx/configs/stm3210e-eval/src/up_nsh.c
@@ -45,7 +45,10 @@
#include <debug.h>
#include <errno.h>
-#include <nuttx/spi.h>
+#ifdef CONFIG_STM32_SPI1
+# include <nuttx/spi.h>
+# include <nuttx/mtd.h>
+#endif
#include <nuttx/mmcsd.h>
/****************************************************************************
@@ -54,6 +57,10 @@
/* Configuration ************************************************************/
+/* For now, don't build in any SPI1 support -- NSH is not using it */
+
+#undef CONFIG_STM32_SPI1
+
/* PORT and SLOT number probably depend on the board configuration */
/* Can't support USB features if USB is not enabled */
@@ -62,23 +69,8 @@
# undef CONFIG_EXAMPLES_NSH_HAVEUSBDEV
#endif
-/* MMC/SD is on SPI1 */
-#warning "MicoSD is on SDIO port, not SPI"
-
-#ifndef CONFIG_STM32_SPI1
-# undef CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO
-# undef CONFIG_EXAMPLES_NSH_MMCSDSLOTNO
-#endif
-
-#if defined(CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO) && CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO != 0
-# error MMC/SD is on SPI1
-# undef CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO
-# undef CONFIG_EXAMPLES_NSH_MMCSDSLOTNO
-#endif
-
#if defined(CONFIG_EXAMPLES_NSH_MMCSDSLOTNO) && CONFIG_EXAMPLES_NSH_MMCSDSLOTNO != 0
# error "Only one MMC/SD slot"
-# undef CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO
# undef CONFIG_EXAMPLES_NSH_MMCSDSLOTNO
#endif
@@ -124,39 +116,44 @@ int nsh_archinitialize(void)
{
#ifdef CONFIG_STM32_SPI1
FAR struct spi_dev_s *spi;
- int ret;
+ FAR struct mtd_dev_s *mtd;
+#endif
- /* Get the SPI port */
+ /* Configure SPI-based devices */
- message("nsh_archinitialize: Initializing SPI port %d\n",
- CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO);
+#ifdef CONFIG_STM32_SPI1
+ /* Get the SPI port */
- spi = up_spiinitialize(CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO);
+ message("nsh_archinitialize: Initializing SPI port 0\n");
+ spi = up_spiinitialize(0);
if (!spi)
{
- message("nsh_archinitialize: Failed to initialize SPI port %d\n",
- CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO);
+ message("nsh_archinitialize: Failed to initialize SPI port 0\n");
return -ENODEV;
}
+ message("nsh_archinitialize: Successfully initialized SPI port 0\n");
- message("nsh_archinitialize: Successfully initialized SPI port %d\n",
- CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO);
-
- /* Bind the SPI port to the slot */
-
- message("nsh_archinitialize: Binding SPI port %d to MMC/SD slot %d\n",
- CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO, CONFIG_EXAMPLES_NSH_MMCSDSLOTNO);
+ /* Now bind the SPI interface to the M25P64/128 SPI FLASH driver */
- ret = mmcsd_spislotinitialize(CONFIG_EXAMPLES_NSH_MMCSDMINOR, CONFIG_EXAMPLES_NSH_MMCSDSLOTNO, spi);
- if (ret < 0)
+ message("nsh_archinitialize: Bind SPI to the SPI flash driver\n");
+ mtd = m25p_initialize(spi);
+ if (!mtd)
{
- message("nsh_archinitialize: Failed to bind SPI port %d to MMC/SD slot %d: %d\n",
- CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO, CONFIG_EXAMPLES_NSH_MMCSDSLOTNO, ret);
- return ret;
+ message("nsh_archinitialize: Failed to bind SPI port 0 to the SPI FLASH driver\n");
+ return -ENODEV;
}
-
- message("nsh_archinitialize: Successfuly bound SPI port %d to MMC/SD slot %d\n",
- CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO, CONFIG_EXAMPLES_NSH_MMCSDSLOTNO);
+ message("nsh_archinitialize: Successfully bound SPI port 0 to the SPI FLASH driver\n");
+#warning "Now what are we going to do with this SPI FLASH driver?"
#endif
+
+ /* Create the SPI FLASH MTD instance */
+
+ /* Here we will eventually need to
+ * 1. Get the SDIO interface instance, and
+ * 2. Bind it to the MMC/SD driver (slot CONFIG_EXAMPLES_NSH_MMCSDSLOTNO,
+ * CONFIG_EXAMPLES_NSH_MMCSDMINOR).
+ */
+
+#warning "Missing MMC/SD device configuration"
return OK;
}
diff --git a/nuttx/configs/stm3210e-eval/src/up_spi.c b/nuttx/configs/stm3210e-eval/src/up_spi.c
index e3bcbf05a..3c2c3e236 100755
--- a/nuttx/configs/stm3210e-eval/src/up_spi.c
+++ b/nuttx/configs/stm3210e-eval/src/up_spi.c
@@ -79,36 +79,6 @@
* Private Functions
************************************************************************************/
-static void stm32_chipselect(FAR struct spi_dev_s *dev, uint32 pinset, boolean pinval, boolean selected)
-{
- spidbg("devid: %d CS: %s pinset: %08x pinval: %s\n",
- (int)devid, selected ? "assert" : "de-assert", pinset, pinval ? "HIGH" : "LOW");
-
- /* If we are selecting the chip, then we must call stm32_spitake to assure that we
- * have mutually exclusive access to the SPI bus while the chip is selected.
- */
-
- if (selected)
- {
- stm32_spitake(dev);
- }
-
- /* Then set the CHIP select. Usually the chip select is LOW to select and HIGH, but
- * that can vary from part to part.
- */
-
- stm32_gpiowrite(pinset, pinval);
-
- /* If we just de-selected the chip, then we must call stm32_spigive to to relinquish
- * our exclusive access to the SPI bus. Now, any waiting threads can have the SPI.
- */
-
- if (!selected)
- {
- stm32_spigive(dev);
- }
-}
-
/************************************************************************************
* Public Functions
************************************************************************************/
@@ -130,10 +100,8 @@ void weak_function stm32_spiinitialize(void)
*/
#ifdef CONFIG_STM32_SPI1
- /* Configure the SPI-based microSD and FLASH CS GPIO */
+ /* Configure the SPI-based FLASH CS GPIO */
-#warning "MicoSD is on SDIO port, not SPI"
- stm32_configgpio(GPIO_MMCSD_CS);
stm32_configgpio(GPIO_FLASH_CS);
#endif
}
@@ -154,9 +122,6 @@ void weak_function stm32_spiinitialize(void)
* 2. Provide stm32_spi1/2/3select() and stm32_spi1/2/3status() functions in your
* board-specific logic. These functions will perform chip selection and
* status operations using GPIOs in the way your board is configured.
- * The select() methods must call stm32_spitake() when the chip is selected
- * and stm32_spigive() when the chip is deselected. This assures mutually
- * exclusive access to the SPI for the duration while a chip is selected.
* 3. Add a calls to up_spiinitialize() in your low level application
* initialization logic
* 4. The handle returned by up_spiinitialize() may then be used to bind the
@@ -171,17 +136,11 @@ void stm32_spi1select(FAR struct spi_dev_s *dev, enum spi_dev_e devid, boolean s
{
spidbg("devid: %d CS: %s\n", (int)devid, selected ? "assert" : "de-assert");
- if (devid == SPIDEV_MMCSD)
- {
- /* Set the GPIO low to select and high to de-select */
-
- stm32_chipselect(dev, GPIO_MMCSD_CS,!selected, selected);
- }
- else if (devid == SPIDEV_FLASH)
+ if (devid == SPIDEV_FLASH)
{
/* Set the GPIO low to select and high to de-select */
- stm32_chipselect(dev, GPIO_FLASH_CS,!selected, selected);
+ stm32_gpiowrite(GPIO_FLASH_CS, !selected);
}
}
diff --git a/nuttx/drivers/mtd/m25px.c b/nuttx/drivers/mtd/m25px.c
index c94c72fa0..f41b49e4b 100644
--- a/nuttx/drivers/mtd/m25px.c
+++ b/nuttx/drivers/mtd/m25px.c
@@ -65,7 +65,7 @@
* (32768 pages) * (256 bytes per page)
*/
-#define M25P_M25P64_SECTOR_SHIFT 16 /* Sector size 1 << 16 = 65,536 */
+#define M25P_M25P64_SECTOR_SHIFT 16 /* Sector size 1 << 16 = 65,536 */
#define M25P_M25P64_NSECTORS 128
#define M25P_M25P64_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */
#define M25P_M25P64_NPAGES 32768
@@ -75,7 +75,7 @@
* (65536 pages) * (256 bytes per page)
*/
-#define M25P_M25P128_SECTOR_SHIFT 18 /* Sector size 1 << 18 = 262,144 */
+#define M25P_M25P128_SECTOR_SHIFT 18 /* Sector size 1 << 18 = 262,144 */
#define M25P_M25P128_NSECTORS 64
#define M25P_M25P128_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */
#define M25P_M25P128_NPAGES 65536
@@ -129,7 +129,7 @@ struct m25p_dev_s
FAR struct spi_dev_s *dev; /* Saved SPI interface instance */
ubyte sectorshift; /* 16 or 18 */
ubyte pageshift; /* 8 */
- uint16 nsectors; /* 128 or 64 */
+ uint16 nsectors; /* 128 or 64 */
uint32 npages; /* 32,768 or 65,536 */
};
@@ -139,6 +139,8 @@ struct m25p_dev_s
/* Helpers */
+static void m25p_lock(FAR struct spi_dev_s *dev);
+static inline void m25p_unlock(FAR struct spi_dev_s *dev);
static inline int m25p_readid(struct m25p_dev_s *priv);
static void m25p_waitwritecomplete(struct m25p_dev_s *priv);
static void m25p_writeenable(struct m25p_dev_s *priv);
@@ -167,6 +169,42 @@ static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
************************************************************************************/
/************************************************************************************
+ * Name: m25p_lock
+ ************************************************************************************/
+
+static void m25p_lock(FAR struct spi_dev_s *dev)
+{
+ /* On SPI busses where there are multiple devices, it will be necessary to
+ * lock SPI to have exclusive access to the busses for a sequence of
+ * transfers. The bus should be locked before the chip is selected.
+ *
+ * This is a blocking call and will not return until we have exclusiv access to
+ * the SPI buss. We will retain that exclusive access until the bus is unlocked.
+ */
+
+ (void)SPI_LOCK(dev, TRUE);
+
+ /* After locking the SPI bus, the we also need call the setfrequency, setbits, and
+ * setmode methods to make sure that the SPI is properly configured for the device.
+ * If the SPI buss is being shared, then it may have been left in an incompatible
+ * state.
+ */
+
+ SPI_SETMODE(dev, SPIDEV_MODE3);
+ SPI_SETBITS(dev, 8);
+ (void)SPI_SETFREQUENCY(dev, 20000000);
+}
+
+/************************************************************************************
+ * Name: m25p_unlock
+ ************************************************************************************/
+
+static inline void m25p_unlock(FAR struct spi_dev_s *dev)
+{
+ (void)SPI_LOCK(dev, FALSE);
+}
+
+/************************************************************************************
* Name: m25p_readid
************************************************************************************/
@@ -178,11 +216,9 @@ static inline int m25p_readid(struct m25p_dev_s *priv)
fvdbg("priv: %p\n", priv);
- /* Select this FLASH part. This is a blocking call and will not return
- * until we have exclusiv access to the SPI buss. We will retain that
- * exclusive access until the chip is de-selected.
- */
+ /* Lock the SPI bus, configure the bus, and select this FLASH part. */
+ m25p_lock(priv->dev);
SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE);
/* Send the "Read ID (RDID)" command and read the first three ID bytes */
@@ -192,12 +228,13 @@ static inline int m25p_readid(struct m25p_dev_s *priv)
memory = SPI_SEND(priv->dev, M25P_DUMMY);
capacity = SPI_SEND(priv->dev, M25P_DUMMY);
- fvdbg("manufacturer: %02x memory: %02x capacity: %02x\n",
- manufacturer, memory, capacity);
-
- /* Deselect the FLASH */
+ /* Deselect the FLASH and unlock the bus */
SPI_SELECT(priv->dev, SPIDEV_FLASH, FALSE);
+ m25p_unlock(priv->dev);
+
+ fvdbg("manufacturer: %02x memory: %02x capacity: %02x\n",
+ manufacturer, memory, capacity);
/* Check for a valid manufacturer and memory type */
@@ -236,10 +273,7 @@ static void m25p_waitwritecomplete(struct m25p_dev_s *priv)
{
ubyte status;
- /* Select this FLASH part. This is a blocking call and will not return
- * until we have exclusiv access to the SPI buss. We will retain that
- * exclusive access until the chip is de-selected.
- */
+ /* Select this FLASH part */
SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE);
@@ -269,10 +303,7 @@ static void m25p_waitwritecomplete(struct m25p_dev_s *priv)
static void m25p_writeenable(struct m25p_dev_s *priv)
{
- /* Select this FLASH part. This is a blocking call and will not return
- * until we have exclusiv access to the SPI buss. We will retain that
- * exclusive access until the chip is de-selected.
- */
+ /* Select this FLASH part */
SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE);
@@ -308,10 +339,7 @@ static inline void m25p_sectorerase(struct m25p_dev_s *priv, off_t sector)
m25p_writeenable(priv);
- /* Select this FLASH part. This is a blocking call and will not return
- * until we have exclusiv access to the SPI buss. We will retain that
- * exclusive access until the chip is de-selected.
- */
+ /* Select this FLASH part */
SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE);
@@ -338,7 +366,7 @@ static inline void m25p_sectorerase(struct m25p_dev_s *priv, off_t sector)
* Name: m25p_bulkerase
************************************************************************************/
-static inline int m25p_bulkerase(struct m25p_dev_s *priv)
+static inline int m25p_bulkerase(struct m25p_dev_s *priv)
{
fvdbg("priv: %p\n", priv);
@@ -354,10 +382,7 @@ static inline int m25p_bulkerase(struct m25p_dev_s *priv)
m25p_writeenable(priv);
- /* Select this FLASH part. This is a blocking call and will not return
- * until we have exclusiv access to the SPI buss. We will retain that
- * exclusive access until the chip is de-selected.
- */
+ /* Select this FLASH part */
SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE);
@@ -395,10 +420,7 @@ static inline void m25p_pagewrite(struct m25p_dev_s *priv, FAR const ubyte *buff
m25p_writeenable(priv);
- /* Select this FLASH part. This is a blocking call and will not return
- * until we have exclusiv access to the SPI buss. We will retain that
- * exclusive access until the chip is de-selected.
- */
+ /* Select this FLASH part */
SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE);
@@ -433,12 +455,17 @@ static int m25p_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblock
fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
+ /* Lock access to the SPI bus until we complete the erase */
+
+ m25p_lock(priv->dev);
while (blocksleft-- > 0)
{
- m25p_sectorerase(priv, startblock);
- startblock++;
- }
+ /* Erase each sector */
+ m25p_sectorerase(priv, startblock);
+ startblock++;
+ }
+ m25p_unlock(priv->dev);
return (int)nblocks;
}
@@ -459,7 +486,7 @@ static ssize_t m25p_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nb
nbytes = m25p_read(dev, startblock << priv->pageshift, nblocks << priv->pageshift, buffer);
if (nbytes > 0)
{
- return nbytes >> priv->pageshift;
+ return nbytes >> priv->pageshift;
}
return nbytes;
}
@@ -476,13 +503,15 @@ static ssize_t m25p_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t n
fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
- /* Write each page to FLASH */
+ /* Lock the SPI bus and write each page to FLASH */
+ m25p_lock(priv->dev);
while (blocksleft-- > 0)
{
m25p_pagewrite(priv, buffer, startblock);
startblock++;
}
+ m25p_unlock(priv->dev);
return nblocks;
}
@@ -506,11 +535,9 @@ static ssize_t m25p_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
m25p_waitwritecomplete(priv);
- /* Select this FLASH part. This is a blocking call and will not return
- * until we have exclusiv access to the SPI buss. We will retain that
- * exclusive access until the chip is de-selected.
- */
+ /* Lock the SPI bus and select this FLASH part */
+ m25p_lock(priv->dev);
SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE);
/* Send "Read from Memory " instruction */
@@ -527,9 +554,10 @@ static ssize_t m25p_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes,
SPI_RECVBLOCK(priv->dev, buffer, nbytes);
- /* Deselect the FLASH */
+ /* Deselect the FLASH and unlock the SPI bus */
SPI_SELECT(priv->dev, SPIDEV_FLASH, FALSE);
+ m25p_unlock(priv->dev);
fvdbg("return nbytes: %d\n", (int)nbytes);
return nbytes;
}
@@ -574,9 +602,11 @@ static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
case MTDIOC_BULKERASE:
{
- /* Erase the entire device */
+ /* Erase the entire device */
- ret = m25p_bulkerase(priv);
+ m25p_lock(priv->dev);
+ ret = m25p_bulkerase(priv);
+ m25p_unlock(priv->dev);
}
break;
@@ -634,12 +664,6 @@ FAR struct mtd_dev_s *m25p_initialize(FAR struct spi_dev_s *dev)
SPI_SELECT(dev, SPIDEV_FLASH, FALSE);
- /* Make sure that SPI is correctly configured from this FLASH */
-
- SPI_SETMODE(dev, SPIDEV_MODE3);
- SPI_SETBITS(dev, 8);
- SPI_SETFREQUENCY(dev, 20000000);
-
/* Identify the FLASH chip and get its capacity */
ret = m25p_readid(priv);
diff --git a/nuttx/include/nuttx/spi.h b/nuttx/include/nuttx/spi.h
index 6630de158..59203d0ec 100644
--- a/nuttx/include/nuttx/spi.h
+++ b/nuttx/include/nuttx/spi.h
@@ -50,6 +50,29 @@
/* Access macros */
/****************************************************************************
+ * Name: SPI_LOCK
+ *
+ * Description:
+ * On SPI busses where there are multiple devices, it will be necessary to
+ * lock SPI to have exclusive access to the busses for a sequence of
+ * transfers. The bus should be locked before the chip is selected. After
+ * locking the SPI bus, the caller should then also call the setfrequency,
+ * setbits, and setmode methods to make sure that the SPI is properly
+ * configured for the device. If the SPI buss is being shared, then it
+ * may have been left in an incompatible state.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * lock - TRUE: Lock spi bus, FALSE: unlock SPI bus
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#define SPI_LOCK(d,l) ((d)->ops->lock ? (d)->ops->lock(d,l) : OK)
+
+/****************************************************************************
* Name: SPI_SELECT
*
* Description:
@@ -296,6 +319,7 @@ enum spi_mode_e
struct spi_dev_s;
struct spi_ops_s
{
+ int (*lock)(FAR struct spi_dev_s *dev, boolean lock);
void (*select)(FAR struct spi_dev_s *dev, enum spi_dev_e devid, boolean selected);
uint32 (*setfrequency)(FAR struct spi_dev_s *dev, uint32 frequency);
void (*setmode)(FAR struct spi_dev_s *dev, enum spi_mode_e mode);