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:
parent
bc8e8d2477
commit
7dfface80c
@ -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
24
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/)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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 };
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user