diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-10-20 14:05:56 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-10-20 14:05:56 +0000 |
commit | 9ad896685124fb84348254f9bafe4fa5f50d9f7b (patch) | |
tree | 48cdf1a94f9920fa25e7ad4744cd5befe6edcc60 /nuttx/arch/arm/src | |
parent | 74ec6c524d7290ebae95c7f2cb126668fdbebbd5 (diff) | |
download | px4-nuttx-9ad896685124fb84348254f9bafe4fa5f50d9f7b.tar.gz px4-nuttx-9ad896685124fb84348254f9bafe4fa5f50d9f7b.tar.bz2 px4-nuttx-9ad896685124fb84348254f9bafe4fa5f50d9f7b.zip |
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
Diffstat (limited to 'nuttx/arch/arm/src')
-rwxr-xr-x | nuttx/arch/arm/src/imx/imx_spi.c | 1 | ||||
-rwxr-xr-x | nuttx/arch/arm/src/lm3s/lm3s_ssi.c | 1 | ||||
-rwxr-xr-x | nuttx/arch/arm/src/stm32/stm32_internal.h | 17 | ||||
-rwxr-xr-x | nuttx/arch/arm/src/stm32/stm32_spi.c | 284 |
4 files changed, 166 insertions, 137 deletions
diff --git a/nuttx/arch/arm/src/imx/imx_spi.c b/nuttx/arch/arm/src/imx/imx_spi.c index f1b3262a0..46cfb6913 100755 --- a/nuttx/arch/arm/src/imx/imx_spi.c +++ b/nuttx/arch/arm/src/imx/imx_spi.c @@ -184,6 +184,7 @@ static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t static const struct spi_ops_s g_spiops = { + .lock = 0, /* Not yet implemented */ .select = imx_spiselect, /* Provided externally by board logic */ .setfrequency = spi_setfrequency, .setmode = spi_setmode, diff --git a/nuttx/arch/arm/src/lm3s/lm3s_ssi.c b/nuttx/arch/arm/src/lm3s/lm3s_ssi.c index 65b01b625..2821dc87e 100755 --- a/nuttx/arch/arm/src/lm3s/lm3s_ssi.c +++ b/nuttx/arch/arm/src/lm3s/lm3s_ssi.c @@ -251,6 +251,7 @@ static void ssi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t static const struct spi_ops_s g_spiops = { + .lock = 0, /* Not yet implemented */ .select = lm3s_spiselect, /* Provided externally by board logic */ .setfrequency = ssi_setfrequency, .setmode = ssi_setmode, diff --git a/nuttx/arch/arm/src/stm32/stm32_internal.h b/nuttx/arch/arm/src/stm32/stm32_internal.h index e5d429be7..58be75b61 100755 --- a/nuttx/arch/arm/src/stm32/stm32_internal.h +++ b/nuttx/arch/arm/src/stm32/stm32_internal.h @@ -610,9 +610,6 @@ EXTERN int stm32_ethinitialize(int intf); * 2. Provide stm32_spi1/2/3select() and stm32_spi1/2/3status() functions in your * board-specific logic. These functions will perform chip selection and * status operations using GPIOs in the way your board is configured. - * The select() methods must call stm32_spitake() when the chip is selected - * and stm32_spigive() when the chip is deselected. This assures mutually - * exclusive access to the SPI for the duration while a chip is selected. * 3. Add a calls to up_spiinitialize() in your low level application * initialization logic * 4. The handle returned by up_spiinitialize() may then be used to bind the @@ -631,20 +628,6 @@ EXTERN ubyte stm32_spi2status(FAR struct spi_dev_s *dev, enum spi_dev_e devid); EXTERN void stm32_spi3select(FAR struct spi_dev_s *dev, enum spi_dev_e devid, boolean selected); EXTERN ubyte stm32_spi3status(FAR struct spi_dev_s *dev, enum spi_dev_e devid); -/************************************************************************************ - * Name: stm32_spitake() and stm32_spigive() - * - * Description: - * The stm32_spi1/2/3select() and stm32_spi1/2/3status() methods must call - * stm32_spitake() when the chip is selected and stm32_spigive() when the chip is - * deselected. This assures mutually exclusive access to the SPI for the duration - * while a chip is selected. - * - ************************************************************************************/ - -EXTERN void stm32_spitake(FAR struct spi_dev_s *dev); -EXTERN void stm32_spigive(FAR struct spi_dev_s *dev); - #undef EXTERN #if defined(__cplusplus) } diff --git a/nuttx/arch/arm/src/stm32/stm32_spi.c b/nuttx/arch/arm/src/stm32/stm32_spi.c index abd9538bb..2ca8989c8 100755 --- a/nuttx/arch/arm/src/stm32/stm32_spi.c +++ b/nuttx/arch/arm/src/stm32/stm32_spi.c @@ -46,9 +46,6 @@ * 2. Provide stm32_spi1/2/3select() and stm32_spi1/2/3status() functions in your * board-specific logic. These functions will perform chip selection and * status operations using GPIOs in the way your board is configured. - * The select() methods must call stm32_spitake() when the chip is selected - * and stm32_spigive() when the chip is deselected. This assures mutually - * exclusive access to the SPI for the duration while a chip is selected. * 3. Add a calls to up_spiinitialize() in your low level application * initialization logic * 4. The handle returned by up_spiinitialize() may then be used to bind the @@ -119,6 +116,10 @@ struct stm32_spidev_s struct spi_dev_s spidev; /* Externally visible part of the SPI interface */ uint32 spibase; /* SPIn base address */ uint32 spiclock; /* Clocking for the SPI module */ + uint32 frequency; /* Requested clock frequency */ + uint32 actual; /* Actual clock frequency */ + ubyte nbits; /* Width of work in bits (8 or 16) */ + ubyte mode; /* Mode 0,1,2,3 */ #ifdef CONFIG_STM32_SPI_INTERRUPTS ubyte spiirq; /* SPI IRQ number */ #endif @@ -167,6 +168,7 @@ static inline void spi_dmatxstart(FAR struct stm32_spidev_s *priv); /* SPI methods */ +static int spi_lock(FAR struct spi_dev_s *dev, boolean lock); static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency); static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode); static void spi_setbits(FAR struct spi_dev_s *dev, int nbits); @@ -191,6 +193,7 @@ static void spi_portinitialize(FAR struct stm32_spidev_s *priv); #ifdef CONFIG_STM32_SPI1 static const struct spi_ops_s g_sp1iops = { + .lock = spi_lock, .select = stm32_spi1select, .setfrequency = spi_setfrequency, .setmode = spi_setmode, @@ -224,6 +227,7 @@ static struct stm32_spidev_s g_spi1dev = #ifdef CONFIG_STM32_SPI2 static const struct spi_ops_s g_sp2iops = { + .lock = spi_lock, .select = stm32_spi2select, .setfrequency = spi_setfrequency, .setmode = spi_setmode, @@ -257,6 +261,7 @@ static struct stm32_spidev_s g_spi2dev = #ifdef CONFIG_STM32_SPI3 static const struct spi_ops_s g_sp3iops = { + .lock = spi_lock, .select = stm32_spi3select, .setfrequency = spi_setfrequency, .setmode = spi_setmode, @@ -664,6 +669,51 @@ static void spi_modifycr1(FAR struct stm32_spidev_s *priv, uint16 setbits, uint1 spi_putreg(priv, STM32_SPI_CR1_OFFSET, cr1); } +/**************************************************************************** + * Name: spi_lock + * + * Description: + * On SPI busses where there are multiple devices, it will be necessary to + * lock SPI to have exclusive access to the busses for a sequence of + * transfers. The bus should be locked before the chip is selected. After + * locking the SPI bus, the caller should then also call the setfrequency, + * setbits, and setmode methods to make sure that the SPI is properly + * configured for the device. If the SPI buss is being shared, then it + * may have been left in an incompatible state. + * + * Input Parameters: + * dev - Device-specific state data + * lock - TRUE: Lock spi bus, FALSE: unlock SPI bus + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int spi_lock(FAR struct spi_dev_s *dev, boolean lock) +{ + FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)dev; + + if (lock) + { + /* Take the semaphore (perhaps waiting) */ + + while (sem_wait(&priv->exclsem) != 0) + { + /* The only case that an error should occur here is if the wait was awakened + * by a signal. + */ + + ASSERT(errno == EINTR); + } + } + else + { + (void)sem_post(&priv->exclsem); + } + return OK; +} + /************************************************************************************ * Name: spi_setfrequency * @@ -685,67 +735,74 @@ static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency) uint16 setbits; uint32 actual; - /* Choices are limited by PCLK frequency with a set of divisors */ + /* Has the frequency changed? */ - if (frequency >= priv->spiclock >> 1) + if (frequency != priv->frequency) { - /* More than fPCLK/2. This is as fast as we can go */ + /* Choices are limited by PCLK frequency with a set of divisors */ - setbits = SPI_CR1_FPCLCKd2; /* 000: fPCLK/2 */ - actual = priv->spiclock >> 1; - } - else if (frequency >= priv->spiclock >> 2) - { - /* Between fPCLCK/2 and fPCLCK/4, pick the slower */ + if (frequency >= priv->spiclock >> 1) + { + /* More than fPCLK/2. This is as fast as we can go */ - setbits = SPI_CR1_FPCLCKd4; /* 001: fPCLK/4 */ - actual = priv->spiclock >> 2; - } - else if (frequency >= priv->spiclock >> 3) - { - /* Between fPCLCK/4 and fPCLCK/8, pick the slower */ + setbits = SPI_CR1_FPCLCKd2; /* 000: fPCLK/2 */ + actual = priv->spiclock >> 1; + } + else if (frequency >= priv->spiclock >> 2) + { + /* Between fPCLCK/2 and fPCLCK/4, pick the slower */ - setbits = SPI_CR1_FPCLCKd8; /* 010: fPCLK/8 */ - actual = priv->spiclock >> 3; - } - else if (frequency >= priv->spiclock >> 4) - { - /* Between fPCLCK/8 and fPCLCK/16, pick the slower */ + setbits = SPI_CR1_FPCLCKd4; /* 001: fPCLK/4 */ + actual = priv->spiclock >> 2; + } + else if (frequency >= priv->spiclock >> 3) + { + /* Between fPCLCK/4 and fPCLCK/8, pick the slower */ - setbits = SPI_CR1_FPCLCKd16; /* 011: fPCLK/16 */ - actual = priv->spiclock >> 4; - } - else if (frequency >= priv->spiclock >> 5) - { - /* Between fPCLCK/16 and fPCLCK/32, pick the slower */ + setbits = SPI_CR1_FPCLCKd8; /* 010: fPCLK/8 */ + actual = priv->spiclock >> 3; + } + else if (frequency >= priv->spiclock >> 4) + { + /* Between fPCLCK/8 and fPCLCK/16, pick the slower */ - setbits = SPI_CR1_FPCLCKd32; /* 100: fPCLK/32 */ - actual = priv->spiclock >> 5; - } - else if (frequency >= priv->spiclock >> 6) - { - /* Between fPCLCK/32 and fPCLCK/64, pick the slower */ + setbits = SPI_CR1_FPCLCKd16; /* 011: fPCLK/16 */ + actual = priv->spiclock >> 4; + } + else if (frequency >= priv->spiclock >> 5) + { + /* Between fPCLCK/16 and fPCLCK/32, pick the slower */ - setbits = SPI_CR1_FPCLCKd64; /* 101: fPCLK/64 */ - actual = priv->spiclock >> 6; - } - else if (frequency >= priv->spiclock >> 7) - { - /* Between fPCLCK/64 and fPCLCK/128, pick the slower */ + setbits = SPI_CR1_FPCLCKd32; /* 100: fPCLK/32 */ + actual = priv->spiclock >> 5; + } + else if (frequency >= priv->spiclock >> 6) + { + /* Between fPCLCK/32 and fPCLCK/64, pick the slower */ - setbits = SPI_CR1_FPCLCKd128; /* 110: fPCLK/128 */ - actual = priv->spiclock >> 7; - } - else - { - /* Less than fPCLK/128. This is as slow as we can go */ + setbits = SPI_CR1_FPCLCKd64; /* 101: fPCLK/64 */ + actual = priv->spiclock >> 6; + } + else if (frequency >= priv->spiclock >> 7) + { + /* Between fPCLCK/64 and fPCLCK/128, pick the slower */ + + setbits = SPI_CR1_FPCLCKd128; /* 110: fPCLK/128 */ + actual = priv->spiclock >> 7; + } + else + { + /* Less than fPCLK/128. This is as slow as we can go */ - setbits = SPI_CR1_FPCLCKd256; /* 111: fPCLK/256 */ - actual = priv->spiclock >> 8; - } + setbits = SPI_CR1_FPCLCKd256; /* 111: fPCLK/256 */ + actual = priv->spiclock >> 8; + } - spi_modifycr1(priv, setbits, SPI_CR1_BR_MASK); - return actual; + spi_modifycr1(priv, setbits, SPI_CR1_BR_MASK); + priv->frequency = frequency; + priv->actual = actual; + } + return priv->actual; } /************************************************************************************ @@ -769,33 +826,41 @@ static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode) uint16 setbits; uint16 clrbits; - switch (mode) + /* Has the mode changed? */ + + if (mode != priv->mode) { - case SPIDEV_MODE0: /* CPOL=0; CPHA=0 */ - setbits = 0; - clrbits = SPI_CR1_CPOL|SPI_CR1_CPHA; - break; + /* Yes... Set CR1 appropriately */ + + switch (mode) + { + case SPIDEV_MODE0: /* CPOL=0; CPHA=0 */ + setbits = 0; + clrbits = SPI_CR1_CPOL|SPI_CR1_CPHA; + break; - case SPIDEV_MODE1: /* CPOL=0; CPHA=1 */ - setbits = SPI_CR1_CPHA; - clrbits = SPI_CR1_CPOL; - break; + case SPIDEV_MODE1: /* CPOL=0; CPHA=1 */ + setbits = SPI_CR1_CPHA; + clrbits = SPI_CR1_CPOL; + break; - case SPIDEV_MODE2: /* CPOL=1; CPHA=0 */ - setbits = SPI_CR1_CPOL; - clrbits = SPI_CR1_CPHA; - break; + case SPIDEV_MODE2: /* CPOL=1; CPHA=0 */ + setbits = SPI_CR1_CPOL; + clrbits = SPI_CR1_CPHA; + break; - case SPIDEV_MODE3: /* CPOL=1; CPHA=1 */ - setbits = SPI_CR1_CPOL|SPI_CR1_CPHA; - clrbits = 0; - break; + case SPIDEV_MODE3: /* CPOL=1; CPHA=1 */ + setbits = SPI_CR1_CPOL|SPI_CR1_CPHA; + clrbits = 0; + break; - default: - return; - } + default: + return; + } - spi_modifycr1(priv, setbits, clrbits); + spi_modifycr1(priv, setbits, clrbits); + priv->mode = mode; + } } /************************************************************************************ @@ -819,23 +884,31 @@ static void spi_setbits(FAR struct spi_dev_s *dev, int nbits) uint16 setbits; uint16 clrbits; - switch (nbits) + /* Has the number of bits changed? */ + + if (nbits != priv->nbits) { - case 8: - setbits = 0; - clrbits = SPI_CR1_DFF; - break; + /* Yes... Set CR1 appropriately */ + + switch (nbits) + { + case 8: + setbits = 0; + clrbits = SPI_CR1_DFF; + break; - case 16: - setbits = SPI_CR1_DFF; - clrbits = 0; - break; + case 16: + setbits = SPI_CR1_DFF; + clrbits = 0; + break; - default: - return; - } + default: + return; + } - spi_modifycr1(priv, setbits, clrbits); + spi_modifycr1(priv, setbits, clrbits); + priv->nbits = nbits; + } } /************************************************************************************ @@ -1094,8 +1167,12 @@ static void spi_portinitialize(FAR struct stm32_spidev_s *priv) setbits = SPI_CR1_MSTR|SPI_CR1_SSI|SPI_CR1_SSM; spi_modifycr1(priv, setbits, clrbits); + priv->nbits = 8; + priv->mode = SPIDEV_MODE0; + /* Select a default frequency of approx. 400KHz */ + priv->frequency = 0; spi_setfrequency((FAR struct spi_dev_s *)priv, 400000); /* CRCPOLY configuration */ @@ -1227,37 +1304,4 @@ FAR struct spi_dev_s *up_spiinitialize(int port) return (FAR struct spi_dev_s *)priv; } -/************************************************************************************ - * Name: stm32_spitake() and stm32_spigive() - * - * Description: - * The stm32_spi1/2/3select() and stm32_spi1/2/3status() methods must call - * stm32_spitake() when the chip is selected and stm32_spigive() when the chip is - * deselected. This assures mutually exclusive access to the SPI for the duration - * while a chip is selected. - * - ************************************************************************************/ - -void stm32_spitake(FAR struct spi_dev_s *dev) -{ - FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)dev; - - /* Take the semaphore (perhaps waiting) */ - - while (sem_wait(&priv->exclsem) != 0) - { - /* The only case that an error should occur here is if the wait was awakened - * by a signal. - */ - - ASSERT(errno == EINTR); - } -} - -void stm32_spigive(FAR struct spi_dev_s *dev) -{ - FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)dev; - (void)sem_post(&priv->exclsem); -} - #endif /* CONFIG_STM32_SPI1 || CONFIG_STM32_SPI2 || CONFIG_STM32_SPI3 */ |