From 4070ce05feae09331156c64b882bead55831f5e3 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 15 Sep 2012 16:02:58 +0000 Subject: [PATCH] Fix a ARMv7-M interrupt disable/optimization bug git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@5155 7fd9a85b-ad96-42d3-883c-3090e2eb8679 --- NxWidgets/UnitTests/README.txt | 30 ++++- nuttx/TODO | 9 +- nuttx/arch/arm/include/armv7-m/irq.h | 112 +++++++++--------- nuttx/arch/arm/src/stm32/stm32_spi.c | 26 ++-- .../configs/fire-stm32v2/src/fire-internal.h | 7 +- nuttx/drivers/net/enc28j60.c | 4 +- 6 files changed, 112 insertions(+), 76 deletions(-) diff --git a/NxWidgets/UnitTests/README.txt b/NxWidgets/UnitTests/README.txt index cc01c38556..9952af0121 100644 --- a/NxWidgets/UnitTests/README.txt +++ b/NxWidgets/UnitTests/README.txt @@ -74,7 +74,7 @@ Installing and Building the Unit Tests writing *ONLY* the sim/nsh2 and stm321-e-eval configurations have C++ support pre-enabled). - c) Enable Debug Options + d) Enable Debug Options If you are running on a simulated target, then you might also want to enable debug symbols: @@ -84,12 +84,12 @@ Installing and Building the Unit Tests Then you can run the simulation using GDB or DDD which is a very powerful debugging environment! - d) Special configuration requirements for the nxwm unit test: + e) Special configuration requirements for the nxwm unit test: CONFIG_NXCONSOLE=y CONFIG_NX_MULTIUSER=y - e) Other nuttx/.config changes -- NSH configurations only. + f) Other nuttx/.config changes -- NSH configurations only. If the configuration that you are using supports NSH and NSH built-in tasks then all is well. If it is an NSH configuration, then you will have to define @@ -101,7 +101,26 @@ Installing and Building the Unit Tests to change anything further in the nuttx/.config file if you are using either of these configurations. - f) Other apps/.config changes -- NON-NSH configurations only. + g) Other apps/.config changes -- NON-NSH configurations only. + + Entry Point. You will need to set the entry point in the .config file. + For NSH configurations, the entry point will always be "nsh_main" and you + will see that setting like: + + CONFIG_USER_ENTRYPOINT="nsh_main" + + If you are not using in NSH, then each unit test has a unique entry point. + That entry point is the name of the unit test directory in all lower case + plus the suffix "_main". So, for example, the correct entry for the + UnitTests/CButton would be: + + CONFIG_USER_ENTRYPOINT="cbutton_main" + + And the correct entry point for UnitTests/nxwm would be: + + CONFIG_USER_ENTRYPOINT="nxwm_main" + + etc. For non-NSH configurations (such as the sim/touchscreen) you will have to remove the CONFIGURED_APPS seting that contains the user_start function so @@ -306,6 +325,9 @@ Example Do nothing... sim/nsh2 already has C++ support enabled. + Since this is an NSH configuration, the entry point does not need to be + changed. + 3. Install the CButton C++ application (for example) Where: /tool diff --git a/nuttx/TODO b/nuttx/TODO index 543d15f707..ae42d6c1c7 100644 --- a/nuttx/TODO +++ b/nuttx/TODO @@ -6,7 +6,7 @@ standards, things that could be improved, and ideas for enhancements. nuttx/ - (5) Task/Scheduler (sched/) + (6) Task/Scheduler (sched/) (1) On-demand paging (sched/) (1) Memory Managment (mm/) (2) Signals (sched/, arch/) @@ -110,6 +110,13 @@ o Task/Scheduler (sched/) Status: Open Priority: Low + Title: posix_spawn() + Description: This would be a good interface to add to NuttX. It is really + just a re-packaging of the existing, non-standard NuttX exec() + function. + Status: Open + Priority: Medium low. + o On-demand paging (sched/) ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/nuttx/arch/arm/include/armv7-m/irq.h b/nuttx/arch/arm/include/armv7-m/irq.h index 6cef85c02a..950ce80ca4 100644 --- a/nuttx/arch/arm/include/armv7-m/irq.h +++ b/nuttx/arch/arm/include/armv7-m/irq.h @@ -129,61 +129,9 @@ struct xcptcontext #ifndef __ASSEMBLY__ -/* Disable IRQs */ - -static inline void irqdisable(void) -{ - __asm__ __volatile__ ("\tcpsid i\n"); -} - -/* Save the current primask state & disable IRQs */ - -static inline irqstate_t irqsave(void) -{ - unsigned short primask; - - /* Return the current value of primask register and set - * bit 0 of the primask register to disable interrupts - */ - - __asm__ __volatile__ - ( - "\tmrs %0, primask\n" - "\tcpsid i\n" - : "=r" (primask) - : - : "memory"); - return primask; -} - -/* Enable IRQs */ - -static inline void irqenable(void) -{ - __asm__ __volatile__ ("\tcpsie i\n"); -} - -/* Restore saved primask state */ - -static inline void irqrestore(irqstate_t primask) -{ - /* If bit 0 of the primask is 0, then we need to restore - * interupts. - */ - - __asm__ __volatile__ - ( - "\ttst %0, #1\n" - "\tbne 1f\n" - "\tcpsie i\n" - "1:\n" - : - : "r" (primask) - : "memory"); -} - /* Get/set the primask register */ +static inline uint8_t getprimask(void) __attribute__((always_inline)); static inline uint8_t getprimask(void) { uint32_t primask; @@ -193,9 +141,44 @@ static inline uint8_t getprimask(void) : "=r" (primask) : : "memory"); + return (uint8_t)primask; } +/* Disable IRQs */ + +static inline void irqdisable(void) __attribute__((always_inline)); +static inline void irqdisable(void) +{ + __asm__ __volatile__ ("\tcpsid i\n"); +} + +/* Save the current primask state & disable IRQs */ + +static inline irqstate_t irqsave(void) __attribute__((always_inline)); +static inline irqstate_t irqsave(void) +{ + /* Return the current value of primask register (before disabling) */ + + uint8_t primask = getprimask(); + + /* Then set bit 0 of the primask register to disable interrupts */ + + irqdisable(); + return primask; +} + +/* Enable IRQs */ + +static inline void irqenable(void) __attribute__((always_inline)); +static inline void irqenable(void) +{ + __asm__ __volatile__ ("\tcpsie i\n"); +} + +/* Restore saved primask state */ + +static inline void setprimask(uint32_t primask) __attribute__((always_inline)); static inline void setprimask(uint32_t primask) { __asm__ __volatile__ @@ -206,20 +189,37 @@ static inline void setprimask(uint32_t primask) : "memory"); } +static inline void irqrestore(irqstate_t primask) __attribute__((always_inline)); +static inline void irqrestore(irqstate_t primask) +{ + /* If bit 0 of the primask is 0, then we need to restore + * interrupts. + */ + + if ((primask & 1) == 0) + { + setprimask(primask); + } +} + /* Get/set the basepri register */ +static inline uint8_t getbasepri(void) __attribute__((always_inline)); static inline uint8_t getbasepri(void) { uint32_t basepri; + __asm__ __volatile__ ( "\tmrs %0, basepri\n" : "=r" (basepri) : : "memory"); + return (uint8_t)basepri; } +static inline void setbasepri(uint32_t basepri) __attribute__((always_inline)); static inline void setbasepri(uint32_t basepri) { __asm__ __volatile__ @@ -232,6 +232,7 @@ static inline void setbasepri(uint32_t basepri) /* Get/set IPSR */ +static inline uint32_t getipsr(void) __attribute__((always_inline)); static inline uint32_t getipsr(void) { uint32_t ipsr; @@ -241,9 +242,11 @@ static inline uint32_t getipsr(void) : "=r" (ipsr) : : "memory"); + return ipsr; } +static inline void setipsr(uint32_t ipsr) __attribute__((always_inline)); static inline void setipsr(uint32_t ipsr) { __asm__ __volatile__ @@ -256,6 +259,7 @@ static inline void setipsr(uint32_t ipsr) /* Get/set CONTROL */ +static inline uint32_t getcontrol(void) __attribute__((always_inline)); static inline uint32_t getcontrol(void) { uint32_t control; @@ -265,9 +269,11 @@ static inline uint32_t getcontrol(void) : "=r" (control) : : "memory"); + return control; } +static inline void setcontrol(uint32_t control) __attribute__((always_inline)); static inline void setcontrol(uint32_t control) { __asm__ __volatile__ diff --git a/nuttx/arch/arm/src/stm32/stm32_spi.c b/nuttx/arch/arm/src/stm32/stm32_spi.c index 40b1a29a09..2d907bfca7 100644 --- a/nuttx/arch/arm/src/stm32/stm32_spi.c +++ b/nuttx/arch/arm/src/stm32/stm32_spi.c @@ -49,7 +49,7 @@ * 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 - * SPI driver to higher level logic (e.g., calling + * SPI driver to higher level logic (e.g., calling * mmcsd_spislotinitialize(), for example, will bind the SPI driver to * the SPI MMC/SD driver). * @@ -881,7 +881,7 @@ static uint32_t spi_setfrequency(FAR struct spi_dev_s *dev, uint32_t frequency) else { /* Less than fPCLK/128. This is as slow as we can go */ - + setbits = SPI_CR1_FPCLCKd256; /* 111: fPCLK/256 */ actual = priv->spiclock >> 8; } @@ -941,22 +941,22 @@ static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode) 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; } @@ -1008,7 +1008,7 @@ static void spi_setbits(FAR struct spi_dev_s *dev, int nbits) setbits = 0; clrbits = SPI_CR1_DFF; break; - + case 16: setbits = SPI_CR1_DFF; clrbits = 0; @@ -1111,7 +1111,7 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, } /* Exchange one word */ - + word = spi_send(dev, word); /* Is there a buffer to receive the return value? */ @@ -1120,7 +1120,7 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, { *dest++ = word; } - } + } } else { @@ -1144,7 +1144,7 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, } /* Exchange one word */ - + word = (uint8_t)spi_send(dev, (uint16_t)word); /* Is there a buffer to receive the return value? */ @@ -1152,7 +1152,7 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer, if (dest) { *dest++ = word; - } + } } } } @@ -1331,7 +1331,7 @@ static void spi_portinitialize(FAR struct stm32_spidev_s *priv) priv->txdma = stm32_dmachannel(priv->txch); DEBUGASSERT(priv->rxdma && priv->txdma); #endif - + /* Enable spi */ spi_modifycr1(priv, SPI_CR1_SPE, 0); @@ -1360,7 +1360,7 @@ FAR struct spi_dev_s *up_spiinitialize(int port) FAR struct stm32_spidev_s *priv = NULL; irqstate_t flags = irqsave(); - + #ifdef CONFIG_STM32_SPI1 if (port == 1) { diff --git a/nuttx/configs/fire-stm32v2/src/fire-internal.h b/nuttx/configs/fire-stm32v2/src/fire-internal.h index 801fb127ea..0260d8e33c 100644 --- a/nuttx/configs/fire-stm32v2/src/fire-internal.h +++ b/nuttx/configs/fire-stm32v2/src/fire-internal.h @@ -214,15 +214,16 @@ # warning "TFT LCD and ENCJ2860 shared PE1" #endif -/* CS and Reset are active low. Initial states are not selected and not in - * reset (driver does a soft reset). +/* CS and Reset are active low. Initial states are not selected and in + * reset. The ENC28J60 is taken out of reset when the driver is + * initialized (thedriver does a soft reset too). */ #ifdef CONFIG_ENC28J60 # define GPIO_ENC28J60_CS (GPIO_OUTPUT|GPIO_CNF_OUTPP|GPIO_MODE_50MHz|\ GPIO_OUTPUT_SET|GPIO_PORTA|GPIO_PIN4) # define GPIO_ENC28J60_RESET (GPIO_OUTPUT|GPIO_CNF_OUTPP|GPIO_MODE_50MHz|\ - GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN1) + GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN1) # define GPIO_ENC28J60_INTR (GPIO_INPUT|GPIO_CNF_INFLOAT|GPIO_MODE_INPUT|\ GPIO_EXTI|GPIO_PORTE|GPIO_PIN5) #endif diff --git a/nuttx/drivers/net/enc28j60.c b/nuttx/drivers/net/enc28j60.c index 47a84ec9f8..df4353b9de 100644 --- a/nuttx/drivers/net/enc28j60.c +++ b/nuttx/drivers/net/enc28j60.c @@ -171,7 +171,7 @@ enum enc_state_e { - ENCSTATE_UNIT = 0, /* The interface is in an unknown state */ + ENCSTATE_UNINIT = 0, /* The interface is in an uninitialized state */ ENCSTATE_DOWN, /* The interface is down */ ENCSTATE_UP /* The interface is up */ }; @@ -2265,7 +2265,7 @@ int enc_initialize(FAR struct spi_dev_s *spi, * bringing the interface up. */ - priv->ifstate = ENCSTATE_UNIT; + priv->ifstate = ENCSTATE_UNINIT; /* Attach the interrupt to the driver (but don't enable it yet) */