Extend SPI interface to better handle multiple devices on same SPI bus

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2162 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2009-10-20 14:05:56 +00:00
parent bc8e8d2477
commit 7dfface80c
14 changed files with 338 additions and 279 deletions

View File

@ -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>

24
TODO
View File

@ -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/)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -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,

View File

@ -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,

View File

@ -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)
}

View File

@ -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,6 +735,10 @@ static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency)
uint16 setbits;
uint32 actual;
/* Has the frequency changed? */
if (frequency != priv->frequency)
{
/* Choices are limited by PCLK frequency with a set of divisors */
if (frequency >= priv->spiclock >> 1)
@ -745,7 +799,10 @@ static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency)
}
spi_modifycr1(priv, setbits, SPI_CR1_BR_MASK);
return actual;
priv->frequency = frequency;
priv->actual = actual;
}
return priv->actual;
}
/************************************************************************************
@ -769,6 +826,12 @@ static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode)
uint16 setbits;
uint16 clrbits;
/* Has the mode changed? */
if (mode != priv->mode)
{
/* Yes... Set CR1 appropriately */
switch (mode)
{
case SPIDEV_MODE0: /* CPOL=0; CPHA=0 */
@ -796,6 +859,8 @@ static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode)
}
spi_modifycr1(priv, setbits, clrbits);
priv->mode = mode;
}
}
/************************************************************************************
@ -819,6 +884,12 @@ static void spi_setbits(FAR struct spi_dev_s *dev, int nbits)
uint16 setbits;
uint16 clrbits;
/* Has the number of bits changed? */
if (nbits != priv->nbits)
{
/* Yes... Set CR1 appropriately */
switch (nbits)
{
case 8:
@ -836,6 +907,8 @@ static void spi_setbits(FAR struct spi_dev_s *dev, int nbits)
}
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 */

View File

@ -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

View File

@ -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 };

View File

@ -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

View File

@ -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)

View File

@ -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
/* Configure SPI-based devices */
#ifdef CONFIG_STM32_SPI1
/* Get the SPI port */
message("nsh_archinitialize: Initializing SPI port %d\n",
CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO);
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);
/* Now bind the SPI interface to the M25P64/128 SPI FLASH driver */
/* 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);
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;
}

View File

@ -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)
if (devid == SPIDEV_FLASH)
{
/* Set the GPIO low to select and high to de-select */
stm32_chipselect(dev, GPIO_MMCSD_CS,!selected, selected);
}
else 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);
}
}

View File

@ -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);
@ -166,6 +168,42 @@ static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg);
* Private Functions
************************************************************************************/
/************************************************************************************
* 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);
@ -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)
{
/* Erase each sector */
m25p_sectorerase(priv, startblock);
startblock++;
}
m25p_unlock(priv->dev);
return (int)nblocks;
}
@ -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;
}
@ -576,7 +604,9 @@ static int m25p_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
/* Erase the entire device */
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);

View File

@ -49,6 +49,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
*
@ -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);