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