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>.
|
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:
|
That structure defines a call table with the following methods:
|
||||||
<ul>
|
<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>
|
<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>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>
|
<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/)
|
(8) ARM/LPC214x (arch/arm/src/lpc214x/)
|
||||||
(3) ARM/STR71x (arch/arm/src/str71x/)
|
(3) ARM/STR71x (arch/arm/src/str71x/)
|
||||||
(3) ARM/LM3S6918 (arch/arm/src/lm3s/)
|
(3) ARM/LM3S6918 (arch/arm/src/lm3s/)
|
||||||
|
(5) ARM/STM32 (arch/arm/src/stm32/)
|
||||||
(4) pjrc-8052 / MCS51 (arch/pjrc-8051/)
|
(4) pjrc-8052 / MCS51 (arch/pjrc-8051/)
|
||||||
(2) Hitachi/Renesas SH-1 (arch/sh/src/sh1)
|
(2) Hitachi/Renesas SH-1 (arch/sh/src/sh1)
|
||||||
(4) Renesas M16C/26 (arch/sh/src/m16c)
|
(4) Renesas M16C/26 (arch/sh/src/m16c)
|
||||||
@ -641,6 +642,29 @@ o ARM/LM3S6918 (arch/arm/src/lm3s/)
|
|||||||
Status: Open
|
Status: Open
|
||||||
Priority: Low -- unless some dependency-related build issues is discovered.
|
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/)
|
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 =
|
static const struct spi_ops_s g_spiops =
|
||||||
{
|
{
|
||||||
|
.lock = 0, /* Not yet implemented */
|
||||||
.select = imx_spiselect, /* Provided externally by board logic */
|
.select = imx_spiselect, /* Provided externally by board logic */
|
||||||
.setfrequency = spi_setfrequency,
|
.setfrequency = spi_setfrequency,
|
||||||
.setmode = spi_setmode,
|
.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 =
|
static const struct spi_ops_s g_spiops =
|
||||||
{
|
{
|
||||||
|
.lock = 0, /* Not yet implemented */
|
||||||
.select = lm3s_spiselect, /* Provided externally by board logic */
|
.select = lm3s_spiselect, /* Provided externally by board logic */
|
||||||
.setfrequency = ssi_setfrequency,
|
.setfrequency = ssi_setfrequency,
|
||||||
.setmode = ssi_setmode,
|
.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
|
* 2. Provide stm32_spi1/2/3select() and stm32_spi1/2/3status() functions in your
|
||||||
* board-specific logic. These functions will perform chip selection and
|
* board-specific logic. These functions will perform chip selection and
|
||||||
* status operations using GPIOs in the way your board is configured.
|
* 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
|
* 3. Add a calls to up_spiinitialize() in your low level application
|
||||||
* initialization logic
|
* initialization logic
|
||||||
* 4. The handle returned by up_spiinitialize() may then be used to bind the
|
* 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 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);
|
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
|
#undef EXTERN
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
|
@ -46,9 +46,6 @@
|
|||||||
* 2. Provide stm32_spi1/2/3select() and stm32_spi1/2/3status() functions in your
|
* 2. Provide stm32_spi1/2/3select() and stm32_spi1/2/3status() functions in your
|
||||||
* board-specific logic. These functions will perform chip selection and
|
* board-specific logic. These functions will perform chip selection and
|
||||||
* status operations using GPIOs in the way your board is configured.
|
* 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
|
* 3. Add a calls to up_spiinitialize() in your low level application
|
||||||
* initialization logic
|
* initialization logic
|
||||||
* 4. The handle returned by up_spiinitialize() may then be used to bind the
|
* 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 */
|
struct spi_dev_s spidev; /* Externally visible part of the SPI interface */
|
||||||
uint32 spibase; /* SPIn base address */
|
uint32 spibase; /* SPIn base address */
|
||||||
uint32 spiclock; /* Clocking for the SPI module */
|
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
|
#ifdef CONFIG_STM32_SPI_INTERRUPTS
|
||||||
ubyte spiirq; /* SPI IRQ number */
|
ubyte spiirq; /* SPI IRQ number */
|
||||||
#endif
|
#endif
|
||||||
@ -167,6 +168,7 @@ static inline void spi_dmatxstart(FAR struct stm32_spidev_s *priv);
|
|||||||
|
|
||||||
/* SPI methods */
|
/* 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 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_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode);
|
||||||
static void spi_setbits(FAR struct spi_dev_s *dev, int nbits);
|
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
|
#ifdef CONFIG_STM32_SPI1
|
||||||
static const struct spi_ops_s g_sp1iops =
|
static const struct spi_ops_s g_sp1iops =
|
||||||
{
|
{
|
||||||
|
.lock = spi_lock,
|
||||||
.select = stm32_spi1select,
|
.select = stm32_spi1select,
|
||||||
.setfrequency = spi_setfrequency,
|
.setfrequency = spi_setfrequency,
|
||||||
.setmode = spi_setmode,
|
.setmode = spi_setmode,
|
||||||
@ -224,6 +227,7 @@ static struct stm32_spidev_s g_spi1dev =
|
|||||||
#ifdef CONFIG_STM32_SPI2
|
#ifdef CONFIG_STM32_SPI2
|
||||||
static const struct spi_ops_s g_sp2iops =
|
static const struct spi_ops_s g_sp2iops =
|
||||||
{
|
{
|
||||||
|
.lock = spi_lock,
|
||||||
.select = stm32_spi2select,
|
.select = stm32_spi2select,
|
||||||
.setfrequency = spi_setfrequency,
|
.setfrequency = spi_setfrequency,
|
||||||
.setmode = spi_setmode,
|
.setmode = spi_setmode,
|
||||||
@ -257,6 +261,7 @@ static struct stm32_spidev_s g_spi2dev =
|
|||||||
#ifdef CONFIG_STM32_SPI3
|
#ifdef CONFIG_STM32_SPI3
|
||||||
static const struct spi_ops_s g_sp3iops =
|
static const struct spi_ops_s g_sp3iops =
|
||||||
{
|
{
|
||||||
|
.lock = spi_lock,
|
||||||
.select = stm32_spi3select,
|
.select = stm32_spi3select,
|
||||||
.setfrequency = spi_setfrequency,
|
.setfrequency = spi_setfrequency,
|
||||||
.setmode = spi_setmode,
|
.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);
|
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
|
* Name: spi_setfrequency
|
||||||
*
|
*
|
||||||
@ -685,67 +735,74 @@ static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency)
|
|||||||
uint16 setbits;
|
uint16 setbits;
|
||||||
uint32 actual;
|
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 */
|
if (frequency >= priv->spiclock >> 1)
|
||||||
actual = priv->spiclock >> 1;
|
{
|
||||||
}
|
/* More than fPCLK/2. This is as fast as we can go */
|
||||||
else if (frequency >= priv->spiclock >> 2)
|
|
||||||
{
|
|
||||||
/* Between fPCLCK/2 and fPCLCK/4, pick the slower */
|
|
||||||
|
|
||||||
setbits = SPI_CR1_FPCLCKd4; /* 001: fPCLK/4 */
|
setbits = SPI_CR1_FPCLCKd2; /* 000: fPCLK/2 */
|
||||||
actual = priv->spiclock >> 2;
|
actual = priv->spiclock >> 1;
|
||||||
}
|
}
|
||||||
else if (frequency >= priv->spiclock >> 3)
|
else if (frequency >= priv->spiclock >> 2)
|
||||||
{
|
{
|
||||||
/* Between fPCLCK/4 and fPCLCK/8, pick the slower */
|
/* Between fPCLCK/2 and fPCLCK/4, pick the slower */
|
||||||
|
|
||||||
setbits = SPI_CR1_FPCLCKd8; /* 010: fPCLK/8 */
|
setbits = SPI_CR1_FPCLCKd4; /* 001: fPCLK/4 */
|
||||||
actual = priv->spiclock >> 3;
|
actual = priv->spiclock >> 2;
|
||||||
}
|
}
|
||||||
else if (frequency >= priv->spiclock >> 4)
|
else if (frequency >= priv->spiclock >> 3)
|
||||||
{
|
{
|
||||||
/* Between fPCLCK/8 and fPCLCK/16, pick the slower */
|
/* Between fPCLCK/4 and fPCLCK/8, pick the slower */
|
||||||
|
|
||||||
setbits = SPI_CR1_FPCLCKd16; /* 011: fPCLK/16 */
|
setbits = SPI_CR1_FPCLCKd8; /* 010: fPCLK/8 */
|
||||||
actual = priv->spiclock >> 4;
|
actual = priv->spiclock >> 3;
|
||||||
}
|
}
|
||||||
else if (frequency >= priv->spiclock >> 5)
|
else if (frequency >= priv->spiclock >> 4)
|
||||||
{
|
{
|
||||||
/* Between fPCLCK/16 and fPCLCK/32, pick the slower */
|
/* Between fPCLCK/8 and fPCLCK/16, pick the slower */
|
||||||
|
|
||||||
setbits = SPI_CR1_FPCLCKd32; /* 100: fPCLK/32 */
|
setbits = SPI_CR1_FPCLCKd16; /* 011: fPCLK/16 */
|
||||||
actual = priv->spiclock >> 5;
|
actual = priv->spiclock >> 4;
|
||||||
}
|
}
|
||||||
else if (frequency >= priv->spiclock >> 6)
|
else if (frequency >= priv->spiclock >> 5)
|
||||||
{
|
{
|
||||||
/* Between fPCLCK/32 and fPCLCK/64, pick the slower */
|
/* Between fPCLCK/16 and fPCLCK/32, pick the slower */
|
||||||
|
|
||||||
setbits = SPI_CR1_FPCLCKd64; /* 101: fPCLK/64 */
|
setbits = SPI_CR1_FPCLCKd32; /* 100: fPCLK/32 */
|
||||||
actual = priv->spiclock >> 6;
|
actual = priv->spiclock >> 5;
|
||||||
}
|
}
|
||||||
else if (frequency >= priv->spiclock >> 7)
|
else if (frequency >= priv->spiclock >> 6)
|
||||||
{
|
{
|
||||||
/* Between fPCLCK/64 and fPCLCK/128, pick the slower */
|
/* Between fPCLCK/32 and fPCLCK/64, pick the slower */
|
||||||
|
|
||||||
setbits = SPI_CR1_FPCLCKd128; /* 110: fPCLK/128 */
|
setbits = SPI_CR1_FPCLCKd64; /* 101: fPCLK/64 */
|
||||||
actual = priv->spiclock >> 7;
|
actual = priv->spiclock >> 6;
|
||||||
}
|
}
|
||||||
else
|
else if (frequency >= priv->spiclock >> 7)
|
||||||
{
|
{
|
||||||
/* Less than fPCLK/128. This is as slow as we can go */
|
/* 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 */
|
setbits = SPI_CR1_FPCLCKd256; /* 111: fPCLK/256 */
|
||||||
actual = priv->spiclock >> 8;
|
actual = priv->spiclock >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
spi_modifycr1(priv, setbits, SPI_CR1_BR_MASK);
|
spi_modifycr1(priv, setbits, SPI_CR1_BR_MASK);
|
||||||
return actual;
|
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 setbits;
|
||||||
uint16 clrbits;
|
uint16 clrbits;
|
||||||
|
|
||||||
switch (mode)
|
/* Has the mode changed? */
|
||||||
{
|
|
||||||
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_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;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
spi_modifycr1(priv, setbits, clrbits);
|
if (mode != priv->mode)
|
||||||
|
{
|
||||||
|
/* 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_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;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 setbits;
|
||||||
uint16 clrbits;
|
uint16 clrbits;
|
||||||
|
|
||||||
switch (nbits)
|
/* Has the number of bits changed? */
|
||||||
|
|
||||||
|
if (nbits != priv->nbits)
|
||||||
{
|
{
|
||||||
case 8:
|
/* Yes... Set CR1 appropriately */
|
||||||
setbits = 0;
|
|
||||||
clrbits = SPI_CR1_DFF;
|
switch (nbits)
|
||||||
break;
|
{
|
||||||
|
case 8:
|
||||||
|
setbits = 0;
|
||||||
|
clrbits = SPI_CR1_DFF;
|
||||||
|
break;
|
||||||
|
|
||||||
case 16:
|
case 16:
|
||||||
setbits = SPI_CR1_DFF;
|
setbits = SPI_CR1_DFF;
|
||||||
clrbits = 0;
|
clrbits = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_modifycr1(priv, setbits, clrbits);
|
||||||
|
priv->nbits = nbits;
|
||||||
}
|
}
|
||||||
|
|
||||||
spi_modifycr1(priv, setbits, clrbits);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
@ -1094,8 +1167,12 @@ static void spi_portinitialize(FAR struct stm32_spidev_s *priv)
|
|||||||
setbits = SPI_CR1_MSTR|SPI_CR1_SSI|SPI_CR1_SSM;
|
setbits = SPI_CR1_MSTR|SPI_CR1_SSI|SPI_CR1_SSM;
|
||||||
spi_modifycr1(priv, setbits, clrbits);
|
spi_modifycr1(priv, setbits, clrbits);
|
||||||
|
|
||||||
|
priv->nbits = 8;
|
||||||
|
priv->mode = SPIDEV_MODE0;
|
||||||
|
|
||||||
/* Select a default frequency of approx. 400KHz */
|
/* Select a default frequency of approx. 400KHz */
|
||||||
|
|
||||||
|
priv->frequency = 0;
|
||||||
spi_setfrequency((FAR struct spi_dev_s *)priv, 400000);
|
spi_setfrequency((FAR struct spi_dev_s *)priv, 400000);
|
||||||
|
|
||||||
/* CRCPOLY configuration */
|
/* CRCPOLY configuration */
|
||||||
@ -1227,37 +1304,4 @@ FAR struct spi_dev_s *up_spiinitialize(int port)
|
|||||||
return (FAR struct spi_dev_s *)priv;
|
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 */
|
#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 =
|
static const struct spi_ops_s g_spiops =
|
||||||
{
|
{
|
||||||
|
0, /* lock() method not yet implemented */
|
||||||
ez80_spiselect, /* Provided externally by board logic */
|
ez80_spiselect, /* Provided externally by board logic */
|
||||||
spi_setfrequency,
|
spi_setfrequency,
|
||||||
spi_setmode,
|
spi_setmode,
|
||||||
@ -85,6 +86,7 @@ static const struct spi_ops_s g_spiops =
|
|||||||
spi_send,
|
spi_send,
|
||||||
spi_sndblock,
|
spi_sndblock,
|
||||||
spi_recvblock,
|
spi_recvblock,
|
||||||
|
0 /* registercallback not yet implemented */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This supports is only a single SPI bus/port. If you port this to an
|
/* 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 =
|
static const struct spi_ops_s g_spiops =
|
||||||
{
|
{
|
||||||
|
.lock = 0, /* Not yet implemented */
|
||||||
.select = spi_select,
|
.select = spi_select,
|
||||||
.setfrequency = spi_setfrequency,
|
.setfrequency = spi_setfrequency,
|
||||||
.status = spi_status,
|
.status = spi_status,
|
||||||
.send = spi_send,
|
.send = spi_send,
|
||||||
.sndblock = spi_sndblock,
|
.sndblock = spi_sndblock,
|
||||||
.recvblock = spi_recvblock,
|
.recvblock = spi_recvblock,
|
||||||
|
.registercallback = 0, /* Not implemented */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct spi_dev_s g_spidev = { &g_spiops };
|
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 =
|
static const struct spi_ops_s g_spiops =
|
||||||
{
|
{
|
||||||
|
.lock = 0, /* Not yet implemented */
|
||||||
.select = spi_select,
|
.select = spi_select,
|
||||||
.setfrequency = spi_setfrequency,
|
.setfrequency = spi_setfrequency,
|
||||||
.status = spi_status,
|
.status = spi_status,
|
||||||
.send = spi_send,
|
.send = spi_send,
|
||||||
.sndblock = spi_sndblock,
|
.sndblock = spi_sndblock,
|
||||||
.recvblock = spi_recvblock,
|
.recvblock = spi_recvblock,
|
||||||
|
.registercallback = 0, /* Not implemented */
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_STR71X_BSPI0
|
#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_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)
|
#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 */
|
/* 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)
|
#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 <debug.h>
|
||||||
#include <errno.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>
|
#include <nuttx/mmcsd.h>
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -54,6 +57,10 @@
|
|||||||
|
|
||||||
/* Configuration ************************************************************/
|
/* 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 */
|
/* PORT and SLOT number probably depend on the board configuration */
|
||||||
|
|
||||||
/* Can't support USB features if USB is not enabled */
|
/* Can't support USB features if USB is not enabled */
|
||||||
@ -62,23 +69,8 @@
|
|||||||
# undef CONFIG_EXAMPLES_NSH_HAVEUSBDEV
|
# undef CONFIG_EXAMPLES_NSH_HAVEUSBDEV
|
||||||
#endif
|
#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
|
#if defined(CONFIG_EXAMPLES_NSH_MMCSDSLOTNO) && CONFIG_EXAMPLES_NSH_MMCSDSLOTNO != 0
|
||||||
# error "Only one MMC/SD slot"
|
# error "Only one MMC/SD slot"
|
||||||
# undef CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO
|
|
||||||
# undef CONFIG_EXAMPLES_NSH_MMCSDSLOTNO
|
# undef CONFIG_EXAMPLES_NSH_MMCSDSLOTNO
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -124,39 +116,44 @@ int nsh_archinitialize(void)
|
|||||||
{
|
{
|
||||||
#ifdef CONFIG_STM32_SPI1
|
#ifdef CONFIG_STM32_SPI1
|
||||||
FAR struct spi_dev_s *spi;
|
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 */
|
/* Get the SPI port */
|
||||||
|
|
||||||
message("nsh_archinitialize: Initializing SPI port %d\n",
|
message("nsh_archinitialize: Initializing SPI port 0\n");
|
||||||
CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO);
|
spi = up_spiinitialize(0);
|
||||||
|
|
||||||
spi = up_spiinitialize(CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO);
|
|
||||||
if (!spi)
|
if (!spi)
|
||||||
{
|
{
|
||||||
message("nsh_archinitialize: Failed to initialize SPI port %d\n",
|
message("nsh_archinitialize: Failed to initialize SPI port 0\n");
|
||||||
CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO);
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
message("nsh_archinitialize: Successfully initialized SPI port 0\n");
|
||||||
|
|
||||||
message("nsh_archinitialize: Successfully initialized SPI port %d\n",
|
/* Now bind the SPI interface to the M25P64/128 SPI FLASH driver */
|
||||||
CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO);
|
|
||||||
|
|
||||||
/* Bind the SPI port to the slot */
|
message("nsh_archinitialize: Bind SPI to the SPI flash driver\n");
|
||||||
|
mtd = m25p_initialize(spi);
|
||||||
message("nsh_archinitialize: Binding SPI port %d to MMC/SD slot %d\n",
|
if (!mtd)
|
||||||
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: Failed to bind SPI port %d to MMC/SD slot %d: %d\n",
|
message("nsh_archinitialize: Failed to bind SPI port 0 to the SPI FLASH driver\n");
|
||||||
CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO, CONFIG_EXAMPLES_NSH_MMCSDSLOTNO, ret);
|
return -ENODEV;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
message("nsh_archinitialize: Successfully bound SPI port 0 to the SPI FLASH driver\n");
|
||||||
message("nsh_archinitialize: Successfuly bound SPI port %d to MMC/SD slot %d\n",
|
#warning "Now what are we going to do with this SPI FLASH driver?"
|
||||||
CONFIG_EXAMPLES_NSH_MMCSDSPIPORTNO, CONFIG_EXAMPLES_NSH_MMCSDSLOTNO);
|
|
||||||
#endif
|
#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;
|
return OK;
|
||||||
}
|
}
|
||||||
|
@ -79,36 +79,6 @@
|
|||||||
* Private Functions
|
* 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
|
* Public Functions
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
@ -130,10 +100,8 @@ void weak_function stm32_spiinitialize(void)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_STM32_SPI1
|
#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);
|
stm32_configgpio(GPIO_FLASH_CS);
|
||||||
#endif
|
#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
|
* 2. Provide stm32_spi1/2/3select() and stm32_spi1/2/3status() functions in your
|
||||||
* board-specific logic. These functions will perform chip selection and
|
* board-specific logic. These functions will perform chip selection and
|
||||||
* status operations using GPIOs in the way your board is configured.
|
* 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
|
* 3. Add a calls to up_spiinitialize() in your low level application
|
||||||
* initialization logic
|
* initialization logic
|
||||||
* 4. The handle returned by up_spiinitialize() may then be used to bind the
|
* 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");
|
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 */
|
/* Set the GPIO low to select and high to de-select */
|
||||||
|
|
||||||
stm32_chipselect(dev, GPIO_MMCSD_CS,!selected, selected);
|
stm32_gpiowrite(GPIO_FLASH_CS, !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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@
|
|||||||
* (32768 pages) * (256 bytes per page)
|
* (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_NSECTORS 128
|
||||||
#define M25P_M25P64_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */
|
#define M25P_M25P64_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */
|
||||||
#define M25P_M25P64_NPAGES 32768
|
#define M25P_M25P64_NPAGES 32768
|
||||||
@ -75,7 +75,7 @@
|
|||||||
* (65536 pages) * (256 bytes per page)
|
* (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_NSECTORS 64
|
||||||
#define M25P_M25P128_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */
|
#define M25P_M25P128_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */
|
||||||
#define M25P_M25P128_NPAGES 65536
|
#define M25P_M25P128_NPAGES 65536
|
||||||
@ -129,7 +129,7 @@ struct m25p_dev_s
|
|||||||
FAR struct spi_dev_s *dev; /* Saved SPI interface instance */
|
FAR struct spi_dev_s *dev; /* Saved SPI interface instance */
|
||||||
ubyte sectorshift; /* 16 or 18 */
|
ubyte sectorshift; /* 16 or 18 */
|
||||||
ubyte pageshift; /* 8 */
|
ubyte pageshift; /* 8 */
|
||||||
uint16 nsectors; /* 128 or 64 */
|
uint16 nsectors; /* 128 or 64 */
|
||||||
uint32 npages; /* 32,768 or 65,536 */
|
uint32 npages; /* 32,768 or 65,536 */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -139,6 +139,8 @@ struct m25p_dev_s
|
|||||||
|
|
||||||
/* Helpers */
|
/* 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 inline int m25p_readid(struct m25p_dev_s *priv);
|
||||||
static void m25p_waitwritecomplete(struct m25p_dev_s *priv);
|
static void m25p_waitwritecomplete(struct m25p_dev_s *priv);
|
||||||
static void m25p_writeenable(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
|
* 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
|
* Name: m25p_readid
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
@ -178,11 +216,9 @@ static inline int m25p_readid(struct m25p_dev_s *priv)
|
|||||||
|
|
||||||
fvdbg("priv: %p\n", priv);
|
fvdbg("priv: %p\n", priv);
|
||||||
|
|
||||||
/* Select this FLASH part. This is a blocking call and will not return
|
/* Lock the SPI bus, configure the bus, and select this FLASH part. */
|
||||||
* until we have exclusiv access to the SPI buss. We will retain that
|
|
||||||
* exclusive access until the chip is de-selected.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
m25p_lock(priv->dev);
|
||||||
SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE);
|
SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE);
|
||||||
|
|
||||||
/* Send the "Read ID (RDID)" command and read the first three ID bytes */
|
/* 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);
|
memory = SPI_SEND(priv->dev, M25P_DUMMY);
|
||||||
capacity = SPI_SEND(priv->dev, M25P_DUMMY);
|
capacity = SPI_SEND(priv->dev, M25P_DUMMY);
|
||||||
|
|
||||||
fvdbg("manufacturer: %02x memory: %02x capacity: %02x\n",
|
/* Deselect the FLASH and unlock the bus */
|
||||||
manufacturer, memory, capacity);
|
|
||||||
|
|
||||||
/* Deselect the FLASH */
|
|
||||||
|
|
||||||
SPI_SELECT(priv->dev, SPIDEV_FLASH, FALSE);
|
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 */
|
/* Check for a valid manufacturer and memory type */
|
||||||
|
|
||||||
@ -236,10 +273,7 @@ static void m25p_waitwritecomplete(struct m25p_dev_s *priv)
|
|||||||
{
|
{
|
||||||
ubyte status;
|
ubyte status;
|
||||||
|
|
||||||
/* Select this FLASH part. This is a blocking call and will not return
|
/* Select this FLASH part */
|
||||||
* until we have exclusiv access to the SPI buss. We will retain that
|
|
||||||
* exclusive access until the chip is de-selected.
|
|
||||||
*/
|
|
||||||
|
|
||||||
SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE);
|
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)
|
static void m25p_writeenable(struct m25p_dev_s *priv)
|
||||||
{
|
{
|
||||||
/* Select this FLASH part. This is a blocking call and will not return
|
/* Select this FLASH part */
|
||||||
* until we have exclusiv access to the SPI buss. We will retain that
|
|
||||||
* exclusive access until the chip is de-selected.
|
|
||||||
*/
|
|
||||||
|
|
||||||
SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE);
|
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);
|
m25p_writeenable(priv);
|
||||||
|
|
||||||
/* Select this FLASH part. This is a blocking call and will not return
|
/* Select this FLASH part */
|
||||||
* until we have exclusiv access to the SPI buss. We will retain that
|
|
||||||
* exclusive access until the chip is de-selected.
|
|
||||||
*/
|
|
||||||
|
|
||||||
SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE);
|
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
|
* 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);
|
fvdbg("priv: %p\n", priv);
|
||||||
|
|
||||||
@ -354,10 +382,7 @@ static inline int m25p_bulkerase(struct m25p_dev_s *priv)
|
|||||||
|
|
||||||
m25p_writeenable(priv);
|
m25p_writeenable(priv);
|
||||||
|
|
||||||
/* Select this FLASH part. This is a blocking call and will not return
|
/* Select this FLASH part */
|
||||||
* until we have exclusiv access to the SPI buss. We will retain that
|
|
||||||
* exclusive access until the chip is de-selected.
|
|
||||||
*/
|
|
||||||
|
|
||||||
SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE);
|
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);
|
m25p_writeenable(priv);
|
||||||
|
|
||||||
/* Select this FLASH part. This is a blocking call and will not return
|
/* Select this FLASH part */
|
||||||
* until we have exclusiv access to the SPI buss. We will retain that
|
|
||||||
* exclusive access until the chip is de-selected.
|
|
||||||
*/
|
|
||||||
|
|
||||||
SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE);
|
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);
|
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)
|
while (blocksleft-- > 0)
|
||||||
{
|
{
|
||||||
m25p_sectorerase(priv, startblock);
|
/* Erase each sector */
|
||||||
startblock++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
m25p_sectorerase(priv, startblock);
|
||||||
|
startblock++;
|
||||||
|
}
|
||||||
|
m25p_unlock(priv->dev);
|
||||||
return (int)nblocks;
|
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);
|
nbytes = m25p_read(dev, startblock << priv->pageshift, nblocks << priv->pageshift, buffer);
|
||||||
if (nbytes > 0)
|
if (nbytes > 0)
|
||||||
{
|
{
|
||||||
return nbytes >> priv->pageshift;
|
return nbytes >> priv->pageshift;
|
||||||
}
|
}
|
||||||
return nbytes;
|
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);
|
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)
|
while (blocksleft-- > 0)
|
||||||
{
|
{
|
||||||
m25p_pagewrite(priv, buffer, startblock);
|
m25p_pagewrite(priv, buffer, startblock);
|
||||||
startblock++;
|
startblock++;
|
||||||
}
|
}
|
||||||
|
m25p_unlock(priv->dev);
|
||||||
|
|
||||||
return nblocks;
|
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);
|
m25p_waitwritecomplete(priv);
|
||||||
|
|
||||||
/* Select this FLASH part. This is a blocking call and will not return
|
/* Lock the SPI bus and select this FLASH part */
|
||||||
* until we have exclusiv access to the SPI buss. We will retain that
|
|
||||||
* exclusive access until the chip is de-selected.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
m25p_lock(priv->dev);
|
||||||
SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE);
|
SPI_SELECT(priv->dev, SPIDEV_FLASH, TRUE);
|
||||||
|
|
||||||
/* Send "Read from Memory " instruction */
|
/* 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);
|
SPI_RECVBLOCK(priv->dev, buffer, nbytes);
|
||||||
|
|
||||||
/* Deselect the FLASH */
|
/* Deselect the FLASH and unlock the SPI bus */
|
||||||
|
|
||||||
SPI_SELECT(priv->dev, SPIDEV_FLASH, FALSE);
|
SPI_SELECT(priv->dev, SPIDEV_FLASH, FALSE);
|
||||||
|
m25p_unlock(priv->dev);
|
||||||
fvdbg("return nbytes: %d\n", (int)nbytes);
|
fvdbg("return nbytes: %d\n", (int)nbytes);
|
||||||
return 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:
|
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;
|
break;
|
||||||
|
|
||||||
@ -634,12 +664,6 @@ FAR struct mtd_dev_s *m25p_initialize(FAR struct spi_dev_s *dev)
|
|||||||
|
|
||||||
SPI_SELECT(dev, SPIDEV_FLASH, FALSE);
|
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 */
|
/* Identify the FLASH chip and get its capacity */
|
||||||
|
|
||||||
ret = m25p_readid(priv);
|
ret = m25p_readid(priv);
|
||||||
|
@ -49,6 +49,29 @@
|
|||||||
|
|
||||||
/* Access macros */
|
/* 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
|
* Name: SPI_SELECT
|
||||||
*
|
*
|
||||||
@ -296,6 +319,7 @@ enum spi_mode_e
|
|||||||
struct spi_dev_s;
|
struct spi_dev_s;
|
||||||
struct spi_ops_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);
|
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);
|
uint32 (*setfrequency)(FAR struct spi_dev_s *dev, uint32 frequency);
|
||||||
void (*setmode)(FAR struct spi_dev_s *dev, enum spi_mode_e mode);
|
void (*setmode)(FAR struct spi_dev_s *dev, enum spi_mode_e mode);
|
||||||
|
Loading…
Reference in New Issue
Block a user