LPC17xx: Hold off sleep mode while DMA is in progress. Open1788: Reverse sense of the IDLE LED

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5810 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2013-04-01 15:52:55 +00:00
parent e185c5404a
commit ff7a38605b
9 changed files with 166 additions and 35 deletions

View File

@ -1161,7 +1161,7 @@
for SPI-based MMC/SD cards and integrate into the NSH example.
* arch/arm/src/lm3s/lm3s_vectors.S: Correct vectors for GPIOC & D
interrupts.
* arch/arm/src/lpc17xx/lp17_clockconfig.c: Power was not being
* arch/arm/src/lpc17xx/lpc17_clockconfig.c: Power was not being
provided to GPIO module. This is a critical bugfix!
* arch/arm/src/lpc17xx/lpc17_serial.c: Improved logic to handle
missed TX interrupts.
@ -1508,7 +1508,7 @@
makes it impossible to kill a background pipe operation from NSH.
* include/stdint.h: Correct some errors in conditional compilation (submitted
by Johannes Hampel).
* arch/arm/lpc17xx/lp17_idle.c: Uses the same logic as the STM32: uses the
* arch/arm/lpc17xx/lpc17_idle.c: Uses the same logic as the STM32: uses the
WFI instruction to sleep in a reduced power mode until the next interrupt
occurs.
* configs/olimex-lpc1766stk: Added an LED encoded to indicate if the LPC1766
@ -4496,3 +4496,12 @@
USARTs that can serve as SPI interfaces as well). These were renamed
to lpc17_spiinitialize() and lpc17_sspinitialize() in this case.
Problem reported by M. Kannan (2014-4-01).
* arch/arm/src/lpc17xx/lpc17_gpdma.c and lpc17_idle.c: In sleep mode,
DMA can only be performed from peripheral SRAM. CPU SRAM is shutdown
in sleep mode. In order to simplify DMA memory allocation, the LPC17xx
IDLE will not hold off going to sleep mode if there is a DMA in progress
(2014-4-01).
* configs/open1788/src/lpc17_autoleds.c: Reversed sense of the IDLE LCD.
It is now off when the LPC17 is sleeping and on when awake. That is
much more useful because it provides a good visual indication of the
dynamic CPU load (2014-4-01).

View File

@ -70,8 +70,9 @@
struct lpc17_dmach_s
{
uint8_t chn; /* The DMA channel number */
bool inuse; /* True: The channel is in use */
uint8_t chn; /* Channel number */
bool inprogress; /* True: DMA is in progress on this channel */
dma_callback_t callback; /* DMA completion callback function */
void *arg; /* Argument to pass to the callback function */
};
@ -102,10 +103,80 @@ static struct lpc17_gpdma_s g_gpdma;
* Public Data
****************************************************************************/
/* If the following value is zero, then there is no DMA in progress. This
* value is needed in the IDLE loop to determine if the IDLE loop should
* go into lower power power consumption modes. According to the LPC17xx
* User Manual: "The DMA controller can continue to work in Sleep mode, and
* has access to the peripheral SRAMs and all peripheral registers. The
* flash memory and the Main SRAM are not available in Sleep mode, they are
* disabled in order to save power."
*/
volatile uint8_t g_dma_inprogress;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: lpc17_dmainprogress
*
* Description:
* Another DMA has started. Increment the g_dma_inprogress counter.
*
* Returned Value:
* None
*
****************************************************************************/
static void lpc17_dmainprogress(struct lpc17_dmach_s *dmach)
{
irqstate_t flags;
/* Increment the DMA in progress counter */
flags = irqsave();
DEBUGASSERT(!dmach->inprogress && g_dma_inprogress < LPC17_NDMACH);
g_dma_inprogress++;
dmach->inprogress = true;
irqrestore(flags);
}
/****************************************************************************
* Name: lpc17_dmadone
*
* Description:
* A DMA has completed. Decrement the g_dma_inprogress counter.
*
* This function is called only from lpc17_dmastop which, in turn, will be
* called either by the user directly, by the user indirectly via
* lpc17_dmafree(), or from gpdma_interrupt when the transfer completes.
*
* NOTE: In the first two cases, we must be able to handle the case where
* there is no DMA in progress and gracefully ignore the call.
*
* Returned Value:
* None
*
****************************************************************************/
static void lpc17_dmadone(struct lpc17_dmach_s *dmach)
{
irqstate_t flags;
/* Increment the DMA in progress counter */
flags = irqsave();
if (dmach->inprogress)
{
DEBUGASSERT(g_dma_inprogress > 0);
dmach->inprogress = false;
g_dma_inprogress--;
}
irqrestore(flags);
}
/****************************************************************************
* Name: gpdma_interrupt
*
@ -488,6 +559,14 @@ int lpc17_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
dmach->callback = callback;
dmach->arg = arg;
/* Increment the count of DMAs in-progress. This count will be
* decremented when lpc17_dmastop() is called, either by the user,
* indirectly via lpc17_dmafree(), or from gpdma_interrupt when the
* transfer completes.
*/
lpc17_dmainprogress(dmach);
/* Clear any pending DMA interrupts */
chbit = DMACH((uint32_t)dmach->chn);
@ -521,6 +600,10 @@ int lpc17_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
* reset and lpc17_dmasetup() must be called before lpc17_dmastart() can be
* called again
*
* This function will be called either by the user directly, by the user
* indirectly via lpc17_dmafree(), or from gpdma_interrupt when the
* transfer completes.
*
****************************************************************************/
void lpc17_dmastop(DMA_HANDLE handle)
@ -547,6 +630,10 @@ void lpc17_dmastop(DMA_HANDLE handle)
chbit = DMACH((uint32_t)dmach->chn);
putreg32(chbit, LPC17_DMA_INTTCCLR);
putreg32(chbit, LPC17_DMA_INTERRCLR);
/* Decrement the count of DMAs in progress */
lpc17_dmadone(dmach);
}
/****************************************************************************

View File

@ -1,4 +1,4 @@
/************************************************************************************
/****************************************************************************
* arch/arm/src/lpc17xx/lpc17_gpdma.h
*
* Copyright (C) 2010, 2013 Gregory Nutt. All rights reserved.
@ -31,36 +31,37 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
****************************************************************************/
#ifndef __ARCH_ARM_SRC_LPC17XX_LPC17_GPDMA_H
#define __ARCH_ARM_SRC_LPC17XX_LPC17_GPDMA_H
/************************************************************************************
/****************************************************************************
* Included Files
************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
#include "chip/lpc17_gpdma.h"
/************************************************************************************
/****************************************************************************
* Pre-processor Definitions
************************************************************************************/
****************************************************************************/
/************************************************************************************
/****************************************************************************
* Public Types
************************************************************************************/
****************************************************************************/
#ifdef CONFIG_LPC17_GPDMA
/* DMA_HANDLE is an opaque reference to an allocated DMA channel */
typedef FAR void *DMA_HANDLE;
/* dma_callback_t a function pointer provided to lpc17_dmastart. This function is
* called at the completion of the DMA transfer. 'arg' is the same 'arg' value
* that was provided when lpc17_dmastart() was called and result indicates the result
* of the transfer: Zero indicates a successful tranfers. On failure, a negated
* errno is returned indicating the general nature of the DMA faiure.
/* dma_callback_t a function pointer provided to lpc17_dmastart. This
* function is called at the completion of the DMA transfer. 'arg' is the
* same 'arg' value that was provided when lpc17_dmastart() was called and
* result indicates the result of the transfer: Zero indicates a successful
* tranfers. On failure, a negated errno is returned indicating the general
* nature of the DMA faiure.
*/
typedef void (*dma_callback_t)(DMA_HANDLE handle, void *arg, int result);
@ -110,19 +111,34 @@ struct lpc17_dmaregs_s
#endif /* CONFIG_DEBUG_DMA */
/************************************************************************************
/****************************************************************************
* Public Data
************************************************************************************/
****************************************************************************/
#ifndef __ASSEMBLY__
#ifdef __cplusplus
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/************************************************************************************
/* If the following value is zero, then there is no DMA in progress. This
* value is needed in the IDLE loop to determine if the IDLE loop should
* go into lower power power consumption modes. According to the LPC17xx
* User Manual: "The DMA controller can continue to work in Sleep mode, and
* has access to the peripheral SRAMs and all peripheral registers. The
* flash memory and the Main SRAM are not available in Sleep mode, they are
* disabled in order to save power."
*/
EXTERN volatile uint8_t g_dma_inprogress;
/****************************************************************************
* Public Functions
************************************************************************************/
****************************************************************************/
/****************************************************************************
* Name: up_dmainitialize
@ -244,6 +260,7 @@ void lpc17_dmadump(DMA_HANDLE handle, const struct lpc17_dmaregs_s *regs,
# define lpc17_dmadump(handle,regs,msg)
#endif
#undef EXTERN
#ifdef __cplusplus
}
#endif

View File

@ -41,7 +41,9 @@
#include <nuttx/config.h>
#include <nuttx/arch.h>
#include "up_internal.h"
#include "lpc17_gpdma.h"
/****************************************************************************
* Pre-processor Definitions
@ -94,11 +96,25 @@ void up_idle(void)
sched_process_timer();
#else
/* Sleep until an interrupt occurs to save power */
/* If the g_dma_inprogress is zero, then there is no DMA in progress. This
* value is needed in the IDLE loop to determine if the IDLE loop should
* go into lower power power consumption modes. According to the LPC17xx
* User Manual: "The DMA controller can continue to work in Sleep mode, and
* has access to the peripheral SRAMs and all peripheral registers. The
* flash memory and the Main SRAM are not available in Sleep mode, they are
* disabled in order to save power."
*/
BEGIN_IDLE();
asm("WFI");
END_IDLE();
#ifdef CONFIG_LPC17_GPDMA
if (g_dma_inprogress == 0)
#endif
{
/* Sleep until an interrupt occurs in order to save power */
BEGIN_IDLE();
asm("WFI");
END_IDLE();
}
#endif
}

View File

@ -39,7 +39,7 @@ the LEDs:
LED_SIGNAL LED3 glows, on while in signal handler
LED_ASSERTION LED3 glows, on while in assertion
LED_PANIC LED3 Flashes at 2Hz
LED_IDLE LED glows, ON while sleeping
LED_IDLE LED glows: ON while active; OFF while sleeping
Buttons
=======

View File

@ -254,7 +254,8 @@
#define LED_SIGNAL 4 /* LED3 glows, on while in signal handler */
#define LED_ASSERTION 4 /* LED3 glows, on while in assertion */
#define LED_PANIC 4 /* LED3 Flashes at 2Hz */
#define LED_IDLE 5 /* LED4 glows, ON while sleeping */
#define LED_IDLE 5 /* LED4 glows: ON while active *
* OFF while sleeping */
/* Button definitions ***************************************************************/
/* The Open1788 supports several buttons. All will read "1" when open and "0"

View File

@ -191,7 +191,8 @@ CONFIG_LPC17_GPDMA=y
#
# SDIO Configuration
#
# CONFIG_SDIO_DMA is not set
CONFIG_SDIO_DMA=y
CONFIG_SDIO_DMAPRIO=0x0
# CONFIG_SDIO_WIDTH_D1_ONLY is not set
#
@ -229,7 +230,7 @@ CONFIG_ARCH_EXTSRAM0HEAP=y
#
# CONFIG_ARCH_NOINTC is not set
# CONFIG_ARCH_VECNOTIRQ is not set
# CONFIG_ARCH_DMA is not set
CONFIG_ARCH_DMA=y
CONFIG_ARCH_IRQPRIO=y
# CONFIG_CUSTOM_STACK is not set
# CONFIG_ADDRENV is not set

View File

@ -173,7 +173,7 @@ CONFIG_LPC17_GPDMA=y
#
# SDIO Configuration
#
# CONFIG_SDIO_DMA is not set
CONFIG_SDIO_DMA=y
CONFIG_SDIO_DMAPRIO=0x0
# CONFIG_SDIO_WIDTH_D1_ONLY is not set
@ -186,7 +186,7 @@ CONFIG_SDIO_DMAPRIO=0x0
#
# CONFIG_ARCH_NOINTC is not set
# CONFIG_ARCH_VECNOTIRQ is not set
# CONFIG_ARCH_DMA is not set
CONFIG_ARCH_DMA=y
CONFIG_ARCH_IRQPRIO=y
# CONFIG_CUSTOM_STACK is not set
# CONFIG_ADDRENV is not set

View File

@ -129,10 +129,10 @@
#define LED_EVENT_OFF_SETBITS ((0) << OFF_SETBITS_SHIFT)
#define LED_EVENT_OFF_CLRBITS ((OPEN1788_LED3) << OFF_CLRBITS_SHIFT)
#define LED_IDLE_ON_SETBITS ((OPEN1788_LED4) << ON_SETBITS_SHIFT)
#define LED_IDLE_ON_CLRBITS ((0) << ON_CLRBITS_SHIFT)
#define LED_IDLE_OFF_SETBITS ((0) << OFF_SETBITS_SHIFT)
#define LED_IDLE_OFF_CLRBITS ((OPEN1788_LED4) << OFF_CLRBITS_SHIFT)
#define LED_IDLE_ON_SETBITS ((0) << ON_SETBITS_SHIFT)
#define LED_IDLE_ON_CLRBITS ((OPEN1788_LED4) << ON_CLRBITS_SHIFT)
#define LED_IDLE_OFF_SETBITS ((OPEN1788_LED4) << OFF_SETBITS_SHIFT)
#define LED_IDLE_OFF_CLRBITS ((0) << OFF_CLRBITS_SHIFT)
/* CONFIG_DEBUG_LEDS enables debug output from this file (needs CONFIG_DEBUG
* with CONFIG_DEBUG_VERBOSE too)