diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html
index 03b8fc720a..9910e4c275 100644
--- a/Documentation/NuttX.html
+++ b/Documentation/NuttX.html
@@ -680,7 +680,10 @@
|
- Graphics: framebuffer drivers, graphic- and segment-LCD drivers.
+
+ Graphics: framebuffer drivers, graphic- and segment-LCD drivers.
+ VNC server.
+
|
@@ -831,7 +834,8 @@
Networking utilities (DHCP server and client, SMTP client, TELNET client, FTP server and client, TFTP client, HTTP server and client, PPPD, NTP client).
- Inheritable TELNET sessions (as "controlling terminal")
+ Inheritable TELNET sessions (as "controlling terminal").
+ VNC server.
|
diff --git a/README.txt b/README.txt
index 570cf1478d..cbba0da1d0 100644
--- a/README.txt
+++ b/README.txt
@@ -833,14 +833,29 @@ Re-building
a file in one of the linked (i.e., copied) directories, re-build NuttX,
and then not see your changes when you run the program. That is because
build is still using the version of the file in the copied directory, not
- your modified file! To work around this annoying behavior, do the
- following when you re-build:
+ your modified file!
+
+ Older versions of NuttX did not support dependiencies in this
+ configuration. So a simple work around this annoying behavior in this
+ case was the following when you re-build:
make clean_context all
This 'make' command will remove of the copied directories, re-copy them,
then make NuttX.
+ However, more recent versions of NuttX do support dependencies for the
+ Cygwin build. As a result, the above command will cause everything to be
+ rebuilt (beause it removes and will cause recreating the
+ include/nuttx/config.h header file). A much less gracefully but still
+ effective command in this case is the following for the ARM configuration:
+
+ rm -rf arch/arm/src/chip arch/arm/src/board
+
+ This "kludge" simple removes the copied directories. These directories
+ will be re-created when you do a normal 'make' and your edits will then be
+ effective.
+
Build Targets and Options
-------------------------
diff --git a/arch/arm/src/stm32l4/Kconfig b/arch/arm/src/stm32l4/Kconfig
index 5bda5de53a..f334ca32bc 100644
--- a/arch/arm/src/stm32l4/Kconfig
+++ b/arch/arm/src/stm32l4/Kconfig
@@ -69,6 +69,34 @@ config STM32L4_FLASH_1024KB
endchoice # Embedded FLASH size
+comment "SRAM2 Options"
+
+config STM32L4_SRAM2_HEAP
+ bool "SRAM2 is used for heap"
+ default n
+ select STM32L4_SRAM2_INIT
+ ---help---
+ The STM32L4 SRAM2 region has special properties (power, protection, parity)
+ which may be used by the application for special purposes. But if these
+ special properties are not needed, it may be instead added to the heap for
+ use by malloc().
+ NOTE: you must also select an appropriate number of memory regions in the
+ 'Memory Management' section.
+
+config STM32L4_SRAM2_INIT
+ bool "SRAM2 is initialized to zero"
+ default n
+ ---help---
+ The STM32L4 SRAM2 region has parity checking. However, when the system
+ powers on, the memory is in an unknown state, and reads from uninitialized
+ memory can trigger parity faults from the random data. This can be
+ avoided by first writing to all locations to force the parity into a valid
+ state.
+ However, if the SRAM2 is being used for it's battery-backed capability,
+ this may be undesireable (because it will destroy the contents). In that
+ case, the board should handle the initialization itself at the appropriate
+ time.
+
menu "STM32L4 Peripheral Support"
# These "hidden" settings determine is a peripheral option is available for the
@@ -79,7 +107,7 @@ config STM32L4_HAVE_LTDC
default n
# These "hidden" settings are the OR of individual peripheral selections
-# indicating that the general capabilitiy is required.
+# indicating that the general capability is required.
config STM32L4_ADC
bool
@@ -133,7 +161,6 @@ config STM32L4_DMA2
select STM32L4_DMA
select ARCH_DMA
-
config STM32L4_CRC
bool "CRC"
default n
@@ -209,7 +236,119 @@ config STM32L4_QSPI_CSHT
---help---
The STM32L4 QSPI peripheral requires that it be specified the minimum number
of AHB cycles that Chip Select be held inactive between transactions.
-
+
+choice
+ prompt "Transfer technique"
+ default STM32L4_QSPI_DMA
+ ---help---
+ You can choose between using polling, interrupts, or DMA to transfer data
+ over the QSPI interface.
+
+config STM32L4_QSPI_POLLING
+ bool "Polling"
+ ---help---
+ Use conventional register I/O with status polling to transfer data.
+
+config STM32L4_QSPI_INTERRUPTS
+ bool "Interrupts"
+ ---help---
+ User interrupt driven I/O transfers.
+
+config STM32L4_QSPI_DMA
+ bool "DMA"
+ depends on STM32L4_DMA
+ ---help---
+ Use DMA to improve QSPI transfer performance.
+
+endchoice
+
+choice
+ prompt "DMA Channel"
+ default STM32L4_QSPI_DMA_CHAN_1_5
+ depends on STM32L4_DMA
+ ---help---
+ You can choose between two DMA channels for use with QSPI:
+ either DMA1 channel 5, or DMA2 channel 7.
+ If you only see one choice here, it is probably because
+ you have not also enabled the associated DMA controller.
+
+config STM32L4_QSPI_DMA_CHAN_1_5
+ bool "DMA1 Channel 5"
+ depends on STM32L4_DMA1
+ ---help---
+ Use DMA1 channel 5 for QSPI.
+
+config STM32L4_QSPI_DMA_CHAN_2_7
+ bool "DMA2 Channel 7"
+ depends on STM32L4_DMA2
+ ---help---
+ Use DMA2 channel 7 for QSPI.
+
+endchoice
+
+choice
+ prompt "DMA Priority"
+ default STM32L4_QSPI_DMAPRIORITY_MEDIUM
+ depends on STM32L4_DMA
+ ---help---
+ The DMA controller supports priority levels. You are probably fine
+ with the default of 'medium' except for special cases. In the event
+ of contention between to channels at the same priority, the lower
+ numbered channel has hardware priority over the higher numbered one.
+
+config STM32L4_QSPI_DMAPRIORITY_VERYHIGH
+ bool "Very High priority"
+ depends on STM32L4_DMA
+ ---help---
+ 'Highest' priority.
+
+config STM32L4_QSPI_DMAPRIORITY_HIGH
+ bool "High priority"
+ depends on STM32L4_DMA
+ ---help---
+ 'High' priority.
+
+config STM32L4_QSPI_DMAPRIORITY_MEDIUM
+ bool "Medium priority"
+ depends on STM32L4_DMA
+ ---help---
+ 'Medium' priority.
+
+config STM32L4_QSPI_DMAPRIORITY_LOW
+ bool "Low priority"
+ depends on STM32L4_DMA
+ ---help---
+ 'Low' priority.
+
+endchoice
+
+config STM32L4_QSPI_DMATHRESHOLD
+ int "QSPI DMA threshold"
+ default 4
+ depends on STM32L4_QSPI_DMA
+ ---help---
+ When QSPI DMA is enabled, small DMA transfers will still be performed
+ by polling logic. This value is the threshold below which transfers
+ will still be performed by conventional register status polling.
+
+config STM32L4_QSPI_DMADEBUG
+ bool "QSPI DMA transfer debug"
+ depends on STM32L4_QSPI_DMA && DEBUG && DEBUG_DMA
+ default n
+ ---help---
+ Enable special debug instrumentation to analyze QSPI DMA data transfers.
+ This logic is as non-invasive as possible: It samples DMA
+ registers at key points in the data transfer and then dumps all of
+ the registers at the end of the transfer.
+
+config STM32L4_QSPI_REGDEBUG
+ bool "QSPI Register level debug"
+ depends on DEBUG
+ default n
+ ---help---
+ Output detailed register-level QSPI device debug information.
+ Requires also DEBUG.
+
endif
comment "APB1 Peripherals"
diff --git a/arch/arm/src/stm32l4/README.txt b/arch/arm/src/stm32l4/README.txt
index bf38fb80ae..59f2eb28d9 100644
--- a/arch/arm/src/stm32l4/README.txt
+++ b/arch/arm/src/stm32l4/README.txt
@@ -23,13 +23,13 @@ LSE : works, but TODO autotrim of MSI, etc
RCC : All registers defined, peripherals enabled, basic clock working
SYSCTL : All registers defined
USART : Working in normal mode (no DMA, to be tested, code is written)
-DMA : Ported from STM32, code written, to be tested
+DMA : works; at least tested with QSPI
SRAM2 : Should work with enough MM regions
FIREWALL : Code written, to be tested, requires support from ldscript
SPI : Code written, to be tested, including DMA
I2C : Registers defined
RTC : works
-QSPI : TODO (port from stm32f7)
+QSPI : works in polling, interrupt, DMA, and also memory-mapped modes
CAN : TODO
OTGFS : TODO
Timers : TODO
diff --git a/arch/arm/src/stm32l4/chip/stm32l4x6xx_dma.h b/arch/arm/src/stm32l4/chip/stm32l4x6xx_dma.h
index c0d136150f..ab63195d2f 100644
--- a/arch/arm/src/stm32l4/chip/stm32l4x6xx_dma.h
+++ b/arch/arm/src/stm32l4/chip/stm32l4x6xx_dma.h
@@ -39,8 +39,7 @@
/************************************************************************************
* Pre-processor Definitions
************************************************************************************/
-/* These definitions apply to both the STM32 F1 and F3 families */
-/* 12 Channels Total: 7 DMA1 Channels(1-7) and 5 DMA2 channels (1-5) */
+/* 14 Channels Total: 7 DMA1 Channels(1-7) and 7 DMA2 channels (1-7) */
#define DMA1 0
#define DMA2 1
@@ -158,6 +157,8 @@
#define STM32L4_DMA2_CCR3 (STM32L4_DMA2_BASE+STM32L4_DMA_CCR3_OFFSET)
#define STM32L4_DMA2_CCR4 (STM32L4_DMA2_BASE+STM32L4_DMA_CCR4_OFFSET)
#define STM32L4_DMA2_CCR5 (STM32L4_DMA2_BASE+STM32L4_DMA_CCR5_OFFSET)
+#define STM32L4_DMA2_CCR6 (STM32L4_DMA2_BASE+STM32L4_DMA_CCR6_OFFSET)
+#define STM32L4_DMA2_CCR7 (STM32L4_DMA2_BASE+STM32L4_DMA_CCR7_OFFSET)
#define STM32L4_DMA2_CNDTR(n) (STM32L4_DMA2_BASE+STM32L4_DMA_CNDTR_OFFSET(n))
#define STM32L4_DMA2_CNDTR1 (STM32L4_DMA2_BASE+STM32L4_DMA_CNDTR1_OFFSET)
@@ -165,6 +166,8 @@
#define STM32L4_DMA2_CNDTR3 (STM32L4_DMA2_BASE+STM32L4_DMA_CNDTR3_OFFSET)
#define STM32L4_DMA2_CNDTR4 (STM32L4_DMA2_BASE+STM32L4_DMA_CNDTR4_OFFSET)
#define STM32L4_DMA2_CNDTR5 (STM32L4_DMA2_BASE+STM32L4_DMA_CNDTR5_OFFSET)
+#define STM32L4_DMA2_CNDTR6 (STM32L4_DMA2_BASE+STM32L4_DMA_CNDTR6_OFFSET)
+#define STM32L4_DMA2_CNDTR7 (STM32L4_DMA2_BASE+STM32L4_DMA_CNDTR7_OFFSET)
#define STM32L4_DMA2_CPAR(n) (STM32L4_DMA2_BASE+STM32L4_DMA_CPAR_OFFSET(n))
#define STM32L4_DMA2_CPAR1 (STM32L4_DMA2_BASE+STM32L4_DMA_CPAR1_OFFSET)
@@ -172,6 +175,8 @@
#define STM32L4_DMA2_CPAR3 (STM32L4_DMA2_BASE+STM32L4_DMA_CPAR3_OFFSET)
#define STM32L4_DMA2_CPAR4 (STM32L4_DMA2_BASE+STM32L4_DMA_CPAR4_OFFSET)
#define STM32L4_DMA2_CPAR5 (STM32L4_DMA2_BASE+STM32L4_DMA_CPAR5_OFFSET)
+#define STM32L4_DMA2_CPAR6 (STM32L4_DMA2_BASE+STM32L4_DMA_CPAR6_OFFSET)
+#define STM32L4_DMA2_CPAR7 (STM32L4_DMA2_BASE+STM32L4_DMA_CPAR7_OFFSET)
#define STM32L4_DMA2_CMAR(n) (STM32L4_DMA2_BASE+STM32L4_DMA_CMAR_OFFSET(n))
#define STM32L4_DMA2_CMAR1 (STM32L4_DMA2_BASE+STM32L4_DMA_CMAR1_OFFSET)
@@ -179,6 +184,8 @@
#define STM32L4_DMA2_CMAR3 (STM32L4_DMA2_BASE+STM32L4_DMA_CMAR3_OFFSET)
#define STM32L4_DMA2_CMAR4 (STM32L4_DMA2_BASE+STM32L4_DMA_CMAR4_OFFSET)
#define STM32L4_DMA2_CMAR5 (STM32L4_DMA2_BASE+STM32L4_DMA_CMAR5_OFFSET)
+#define STM32L4_DMA2_CMAR6 (STM32L4_DMA2_BASE+STM32L4_DMA_CMAR6_OFFSET)
+#define STM32L4_DMA2_CMAR7 (STM32L4_DMA2_BASE+STM32L4_DMA_CMAR7_OFFSET)
/* Register Bitfield Definitions ****************************************************/
diff --git a/arch/arm/src/stm32l4/stm32l4_allocateheap.c b/arch/arm/src/stm32l4/stm32l4_allocateheap.c
index e1c2e1acaf..9e37373adf 100644
--- a/arch/arm/src/stm32l4/stm32l4_allocateheap.c
+++ b/arch/arm/src/stm32l4/stm32l4_allocateheap.c
@@ -62,13 +62,13 @@
****************************************************************************/
/* Internal SRAM is available in all members of the STM32L4 family. The
* following definitions must be provided to specify the size and
- * location of internal(system) SRAM:
+ * location of internal (system) SRAM1 and SRAM2:
*
* SRAM1_END 0x20018000
* SRAM2_START 0x10000000
* SRAM2_END 0x10008000
*
- * In addition to internal SRAM, SRAM may also be available through the FSMC.
+ * In addition to internal SRAM, memory may also be available through the FSMC.
* In order to use FSMC SRAM, the following additional things need to be
* present in the NuttX configuration file:
*
@@ -80,15 +80,14 @@
* CONFIG_HEAP2_SIZE : The size of the SRAM in the FSMC
* address space
* CONFIG_MM_REGIONS : Must be set to a large enough value to
- * include the FSMC SRAM (as determined by
- * the rules provided below)
+ * include the additional regions.
*/
#ifndef CONFIG_STM32L4_FSMC
# undef CONFIG_STM32L4_FSMC_SRAM
#endif
-/* MSTM32L4x6xx have 128Kib in two banks, both accessible to DMA:
+/* STM32L4x6xx have 128Kib in two banks, both accessible to DMA:
*
* 1) 96KiB of System SRAM beginning at address 0x2000:0000 - 0x2001:8000
* 2) 32KiB of System SRAM beginning at address 0x1000:0000 - 0x1000:8000
@@ -105,55 +104,21 @@
#define SRAM2_START 0x10000000
#define SRAM2_END 0x10008000
-/* Allocations according to the number of memory regions:
- *
- * 1 region available:
- * - map it to SRAM1
- * - warn that SRAM2 is not available for heap
- * - if FMC is enabled, warn that it is not available for heap
- *
- * 2 regions available: map them to SRAM1 and SRAM2
- * - map region 1 to SRAM1
- * - map region 2 to SRAM2
- * - if FMC is enabled, warn that it is not available for heap
- *
- * 3 or more regions
- *
- * - map them to SRAM1, SRAM2, FMC
- */
-
-#if CONFIG_MM_REGIONS < 1
-# warning heap is not usable
-
-#elif CONFIG_MM_REGIONS < 2
-
-# warning SRAM2 (32k) is NOT available for heap, only SRAM1 (96k) : not enough MM regions
-# undef SRAM2_START
-# undef SRAM2_END
-
-# if defined(CONFIG_STM32L4_FSMC_SRAM)
-# warning FMC SRAM is NOT available for heap : not enough MM regions (1)
-# undef CONFIG_STM32L4_FSMC_SRAM
+#if defined(STM32L4_SRAM2_HEAP) && defined(CONFIG_STM32L4_FSMC_SRAM_HEAP)
+# if CONFIG_MM_REGIONS < 3
+# error you need at least 3 memory manager regions to support SRAM2 and FSMC
# endif
-
-#elif CONFIG_MM_REGIONS < 3
-
-# if defined(CONFIG_STM32L4_FSMC_SRAM)
-# warning FMC SRAM is NOT available for heap : not enough MM regions (2)
-# undef CONFIG_STM32L4_FSMC_SRAM
-# endif
-
-#elif CONFIG_MM_REGIONS > 3
-
-/*Everything can be mapped but some entries wont be used -> warn and correct*/
-# warning "CONFIG_MM_REGIONS > 3 but I don't know what some of the region(s) are"
-# undef CONFIG_MM_REGIONS
-# define CONFIG_MM_REGIONS 3
-
-#else
-/*Everything can be mapped*/
#endif
+#if defined(STM32L4_SRAM2_HEAP) || defined(CONFIG_STM32L4_FSMC_SRAM_HEAP)
+# if CONFIG_MM_REGIONS < 2
+# error you need at least 2 memory manager regions to support SRAM2 or FSMC
+# endif
+#endif
+
+#if CONFIG_MM_REGIONS < 1
+# warning you have no heap; malloc() will fail. are you sure?
+#endif
/* If FSMC SRAM is going to be used as heap, then verify that the starting
* address and size of the external SRAM region has been provided in the
@@ -338,6 +303,8 @@ void up_allocate_kheap(FAR void **heap_start, size_t *heap_size)
void up_addregion(void)
{
+#ifdef CONFIG_STM32L4_SRAM2_HEAP
+
#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP)
/* Allow user-mode access to the SRAM2 heap */
@@ -354,7 +321,9 @@ void up_addregion(void)
kumm_addregion((FAR void *)SRAM2_START, SRAM2_END-SRAM2_START);
-#ifdef CONFIG_STM32L4_FSMC_SRAM
+#endif
+
+#ifdef CONFIG_STM32L4_FSMC_SRAM_HEAP
#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MM_KERNEL_HEAP)
/* Allow user-mode access to the FSMC SRAM user heap memory */
diff --git a/arch/arm/src/stm32l4/stm32l4_dma.h b/arch/arm/src/stm32l4/stm32l4_dma.h
index 9fd36a6337..ee11f8655c 100644
--- a/arch/arm/src/stm32l4/stm32l4_dma.h
+++ b/arch/arm/src/stm32l4/stm32l4_dma.h
@@ -3,6 +3,8 @@
*
* Copyright (C) 2009, 2011-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
+ * Sebastien Lorquet
+ * dev@ziggurat29.com
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -57,13 +59,11 @@
* DMA callback function (see dma_callback_t).
*/
-# define DMA_STATUS_FEIF 0 /* (Not available in F1) */
-# define DMA_STATUS_DMEIF 0 /* (Not available in F1) */
# define DMA_STATUS_TEIF DMA_CHAN_TEIF_BIT /* Channel Transfer Error */
# define DMA_STATUS_HTIF DMA_CHAN_HTIF_BIT /* Channel Half Transfer */
# define DMA_STATUS_TCIF DMA_CHAN_TCIF_BIT /* Channel Transfer Complete */
-#define DMA_STATUS_ERROR (DMA_STATUS_FEIF|DMA_STATUS_DMEIF|DMA_STATUS_TEIF)
+#define DMA_STATUS_ERROR (DMA_STATUS_TEIF)
#define DMA_STATUS_SUCCESS (DMA_STATUS_TCIF|DMA_STATUS_HTIF)
/************************************************************************************
@@ -71,7 +71,7 @@
************************************************************************************/
/* DMA_HANDLE provides an opaque are reference that can be used to represent a DMA
- * channel (F1) or a DMA stream (F4).
+ * channel.
*/
typedef FAR void *DMA_HANDLE;
@@ -81,7 +81,7 @@ typedef FAR void *DMA_HANDLE;
* completion of the DMA.
*
* Input Parameters:
- * handle - Refers tot he DMA channel or stream
+ * handle - Refers tot he DMA channel
* status - A bit encoded value that provides the completion status. See the
* DMASTATUS_* definitions above.
* arg - A user-provided value that was provided when stm32l4_dmastart() was
@@ -93,11 +93,12 @@ typedef void (*dma_callback_t)(DMA_HANDLE handle, uint8_t status, void *arg);
#ifdef CONFIG_DEBUG_DMA
struct stm32l4_dmaregs_s
{
- uint32_t isr;
- uint32_t ccr;
- uint32_t cndtr;
- uint32_t cpar;
- uint32_t cmar;
+ uint32_t isr; /* Interrupt Status Register; each channel gets 4 bits */
+ uint32_t cselr; /* Channel Selection Register; chooses peripheral bound */
+ uint32_t ccr; /* Channel Configuration Register; determines functionality */
+ uint32_t cndtr; /* Channel Count Register; determines number of transfers */
+ uint32_t cpar; /* Channel Peripheral Address Register; determines start */
+ uint32_t cmar; /* Channel Memory Address Register; determines start */
};
#endif
@@ -126,7 +127,7 @@ extern "C"
* Description:
* Allocate a DMA channel. This function gives the caller mutually
* exclusive access to the DMA channel specified by the 'chan' argument.
- * DMA channels are shared on the STM32: Devices sharing the same DMA
+ * DMA channels are shared on the STM32L4: Devices sharing the same DMA
* channel cannot do DMA concurrently! See the DMACHAN_* definitions in
* stm32l4_dma.h.
*
@@ -142,10 +143,8 @@ extern "C"
*
* Input parameter:
* chan - Identifies the stream/channel resource
- * For the STM32 F1, this is simply the channel number as provided by
- * the DMACHAN_* definitions in chip/stm32f10xxx_dma.h.
- * For the STM32 F4, this is a bit encoded value as provided by the
- * the DMAMAP_* definitions in chip/stm32f40xxx_dma.h
+ * This is a bit encoded value as provided by the DMACHAN_* definitions
+ * in chip/stm32l4x6xx_dma.h
*
* Returned Value:
* Provided that 'chan' is valid, this function ALWAYS returns a non-NULL,
@@ -153,8 +152,8 @@ extern "C"
* assert if debug is enabled or do something ignorant otherwise).
*
* Assumptions:
- * - The caller does not hold he DMA channel.
- * - The caller can wait for the DMA channel to be freed if it is no
+ * - The caller does not hold the DMA channel.
+ * - The caller can wait for the DMA channel to be freed if it is not
* available.
*
****************************************************************************/
diff --git a/arch/arm/src/stm32l4/stm32l4_qspi.c b/arch/arm/src/stm32l4/stm32l4_qspi.c
index d9c9ca5825..57aa85dac0 100644
--- a/arch/arm/src/stm32l4/stm32l4_qspi.c
+++ b/arch/arm/src/stm32l4/stm32l4_qspi.c
@@ -120,18 +120,12 @@
#define DMA_END_TRANSFER 4
#define DMA_NSAMPLES 5
-#ifdef CONFIG_STM32L4_QSPI_DMA
-# error QSPI DMA support not yet implemented
+/* Can't have both interrupt-driven QSPI and DMA QSPI */
+
+#if defined(STM32L4_QSPI_INTERRUPTS) && defined(CONFIG_STM32L4_QSPI_DMA)
+# error "Cannot enable both interrupt mode and DMA mode for QSPI"
#endif
-/* QSPI dma is not yet implemented */
-
-#undef CONFIG_STM32L4_QSPI_DMA
-
-/* QSPI Interrupt mode is implemented */
-
-#define QSPI_USE_INTERRUPTS
-
/* Sanity check that board.h defines requisite QSPI pinmap options for */
#if (!defined(GPIO_QSPI_CS) || !defined(GPIO_QSPI_IO0) || !defined(GPIO_QSPI_IO1) || \
@@ -141,9 +135,27 @@
#endif
#ifdef CONFIG_STM32L4_QSPI_DMA
-# if !defined(DMACHAN_QUADSPI)
+
+# if defined(CONFIG_STM32L4_QSPI_DMA_CHAN_1_5)
+# define DMACHAN_QUADSPI DMACHAN_QUADSPI_1
+# elif defined(CONFIG_STM32L4_QSPI_DMA_CHAN_2_7)
+# define DMACHAN_QUADSPI DMACHAN_QUADSPI_2
+# else
# error QSPI DMA channel must be specified via DMACHAN_QUADSPI in your board.h
# endif
+
+# if defined(CONFIG_STM32L4_QSPI_DMAPRIORITY_LOW)
+# define QSPI_DMA_PRIO DMA_CCR_PRILO
+# elif defined(CONFIG_STM32L4_QSPI_DMAPRIORITY_MEDIUM)
+# define QSPI_DMA_PRIO DMA_CCR_PRIMED
+# elif defined(CONFIG_STM32L4_QSPI_DMAPRIORITY_HIGH)
+# define QSPI_DMA_PRIO DMA_CCR_PRIHI
+# elif defined(CONFIG_STM32L4_QSPI_DMAPRIORITY_VERYHIGH)
+# define QSPI_DMA_PRIO DMA_CCR_PRIVERYHI
+# else
+# define QSPI_DMA_PRIO DMA_CCR_PRIMED
+# endif
+
#endif
#ifndef BOARD_AHB_FREQUENCY
@@ -154,6 +166,13 @@
# error you must specify a positive flash size via CONFIG_STM32L4_QSPI_FLASH_SIZE
#endif
+/* DMA timeout. The value is not critical; we just don't want the system to
+ * hang in the event that a DMA does not finish.
+ */
+
+#define DMA_TIMEOUT_MS (800)
+#define DMA_TIMEOUT_TICKS MSEC2TICK(DMA_TIMEOUT_MS)
+
/* Clocking *****************************************************************/
/* The QSPI bit rate clock is generated by dividing the peripheral clock by
* a value between 1 and 255
@@ -184,7 +203,7 @@ struct stm32l4_qspidev_s
sem_t exclsem; /* Assures mutually exclusive access to QSPI */
bool memmap; /* TRUE: Controller is in memory mapped mode */
-#ifdef QSPI_USE_INTERRUPTS
+#ifdef STM32L4_QSPI_INTERRUPTS
xcpt_t handler; /* Interrupt handler */
uint8_t irq; /* Interrupt number */
sem_t op_sem; /* Block until complete */
@@ -192,7 +211,11 @@ struct stm32l4_qspidev_s
#endif
#ifdef CONFIG_STM32L4_QSPI_DMA
- /* XXX III needs implementation */
+ bool candma; /* DMA is supported */
+ sem_t dmawait; /* Used to wait for DMA completion */
+ int result; /* DMA result */
+ DMA_HANDLE dmach; /* QSPI DMA handle */
+ WDOG_ID dmadog; /* Watchdog that handles DMA timeouts */
#endif
/* Debug stuff */
@@ -238,7 +261,7 @@ struct qspi_xctnspec_s
uint8_t isddr; /* true if 'double data rate' */
uint8_t issioo; /* true if 'send instruction only once' mode */
-#ifdef QSPI_USE_INTERRUPTS
+#ifdef STM32L4_QSPI_INTERRUPTS
uint8_t function; /* functional mode; to distinguish a read or write */
int8_t disposition; /* how it all turned out */
uint32_t idxnow; /* index into databuffer of current byte in transfer */
@@ -277,11 +300,37 @@ static void qspi_dumpgpioconfig(const char *msg);
/* Interrupts */
-#ifdef QSPI_USE_INTERRUPTS
+#ifdef STM32L4_QSPI_INTERRUPTS
static int qspi0_interrupt(int irq, void *context);
#endif
+/* DMA support */
+
+#ifdef CONFIG_STM32L4_QSPI_DMA
+
+# if defined(CONFIG_QSPI_DMAPRIO)
+# define QSPI_DMA_PRIO CONFIG_QSPI_DMAPRIO
+# else
+# define QSPI_DMA_PRIO DMA_CCR_PRIMED
+# endif
+
+# ifdef CONFIG_STM32L4_QSPI_DMADEBUG
+# define qspi_dma_sample(s,i) stm32l4_dmasample((s)->dmach, &(s)->dmaregs[i])
+static void qspi_dma_sampleinit(struct stm32l4_qspidev_s *priv);
+static void qspi_dma_sampledone(struct stm32l4_qspidev_s *priv);
+# else
+# define qspi_dma_sample(s,i)
+# define qspi_dma_sampleinit(s)
+# define qspi_dma_sampledone(s)
+# endif
+
+# ifndef CONFIG_STM32L4_QSPI_DMATHRESHOLD
+# define CONFIG_STM32L4_QSPI_DMATHRESHOLD 4
+# endif
+
+#endif
+
/* QSPI methods */
static int qspi_lock(struct qspi_dev_s *dev, bool lock);
@@ -326,13 +375,13 @@ static struct stm32l4_qspidev_s g_qspi0dev =
.ops = &g_qspi0ops,
},
.base = STM32L4_QSPI_BASE,
-#ifdef QSPI_USE_INTERRUPTS
+#ifdef STM32L4_QSPI_INTERRUPTS
.handler = qspi0_interrupt,
.irq = STM32L4_IRQ_QUADSPI,
#endif
.intf = 0,
#ifdef CONFIG_STM32L4_QSPI_DMA
- /* XXX III needs implementation */
+ .candma = true,
#endif
};
@@ -572,6 +621,93 @@ static void qspi_dumpgpioconfig(const char *msg)
}
#endif
+#ifdef CONFIG_STM32L4_QSPI_DMADEBUG
+/****************************************************************************
+ * Name: qspi_dma_sampleinit
+ *
+ * Description:
+ * Initialize sampling of DMA registers
+ *
+ * Input Parameters:
+ * priv - QSPI driver instance
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void qspi_dma_sampleinit(struct stm32l4_qspidev_s *priv)
+{
+ /* Put contents of register samples into a known state */
+
+ memset(priv->dmaregs, 0xff, DMA_NSAMPLES * sizeof(struct stm32l4_dmaregs_s));
+
+ /* Then get the initial samples */
+
+ stm32l4_dmasample(priv->dmach, &priv->dmaregs[DMA_INITIAL]);
+}
+
+/****************************************************************************
+ * Name: qspi_dma_sampledone
+ *
+ * Description:
+ * Dump sampled DMA registers
+ *
+ * Input Parameters:
+ * priv - QSPI driver instance
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void qspi_dma_sampledone(struct stm32l4_qspidev_s *priv)
+{
+ /* Sample the final registers */
+
+ stm32l4_dmasample(priv->dmach, &priv->dmaregs[DMA_END_TRANSFER]);
+
+ /* Then dump the sampled DMA registers */
+ /* Initial register values */
+
+ stm32l4_dmadump(priv->dmach, &priv->dmaregs[DMA_INITIAL],
+ "Initial Registers");
+
+ /* Register values after DMA setup */
+
+ stm32l4_dmadump(priv->dmach, &priv->dmaregs[DMA_AFTER_SETUP],
+ "After DMA Setup");
+
+ /* Register values after DMA start */
+
+ stm32l4_dmadump(priv->dmach, &priv->dmaregs[DMA_AFTER_START],
+ "After DMA Start");
+
+ /* Register values at the time of the TX and RX DMA callbacks
+ * -OR- DMA timeout.
+ *
+ * If the DMA timed out, then there will not be any RX DMA
+ * callback samples. There is probably no TX DMA callback
+ * samples either, but we don't know for sure.
+ */
+
+ if (priv->result == -ETIMEDOUT)
+ {
+ stm32l4_dmadump(priv->dmach, &priv->dmaregs[DMA_TIMEOUT],
+ "At DMA timeout");
+ }
+ else
+ {
+ stm32l4_dmadump(priv->dmach, &priv->dmaregs[DMA_CALLBACK],
+ "At DMA callback");
+ }
+
+ stm32l4_dmadump(priv->dmach, &priv->dmaregs[DMA_END_TRANSFER],
+ "At End-of-Transfer");
+}
+#endif
+
+
/****************************************************************************
* Name: qspi_setupxctnfromcmd
*
@@ -687,7 +823,7 @@ static int qspi_setupxctnfromcmd(struct qspi_xctnspec_s *xctn,
xctn->isddr = 0;
}
-#if defined(QSPI_USE_INTERRUPTS)
+#if defined(STM32L4_QSPI_INTERRUPTS)
xctn->function = QSPICMD_ISWRITE(cmdinfo->flags) ? CCR_FMODE_INDWR : CCR_FMODE_INDRD;
xctn->disposition = - EIO;
xctn->idxnow = 0;
@@ -816,7 +952,7 @@ static int qspi_setupxctnfrommem(struct qspi_xctnspec_s *xctn,
xctn->isddr = 0;
-#if defined(QSPI_USE_INTERRUPTS)
+#if defined(STM32L4_QSPI_INTERRUPTS)
xctn->function = QSPIMEM_ISWRITE(meminfo->flags) ? CCR_FMODE_INDWR : CCR_FMODE_INDRD;
xctn->disposition = - EIO;
xctn->idxnow = 0;
@@ -938,7 +1074,7 @@ static void qspi_ccrconfig(struct stm32l4_qspidev_s *priv,
}
}
-#if defined(QSPI_USE_INTERRUPTS)
+#if defined(STM32L4_QSPI_INTERRUPTS)
/****************************************************************************
* Name: qspi0_interrupt
*
@@ -1146,9 +1282,267 @@ static int qspi0_interrupt(int irq, void *context)
}
#elif defined(CONFIG_STM32L4_QSPI_DMA)
- /* XXX III dma mode */
+/****************************************************************************
+ * Name: qspi_dma_timeout
+ *
+ * Description:
+ * The watchdog timeout setup when a has expired without completion of a
+ * DMA.
+ *
+ * Input Parameters:
+ * argc - The number of arguments (should be 1)
+ * arg - The argument (state structure reference cast to uint32_t)
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Always called from the interrupt level with interrupts disabled.
+ *
+ ****************************************************************************/
-#else
+static void qspi_dma_timeout(int argc, uint32_t arg)
+{
+ struct stm32l4_qspidev_s *priv = (struct stm32l4_qspidev_s *)arg;
+ DEBUGASSERT(priv != NULL);
+
+ /* Sample DMA registers at the time of the timeout */
+
+ qspi_dma_sample(priv, DMA_CALLBACK);
+
+ /* Report timeout result, perhaps overwriting any failure reports from
+ * the TX callback.
+ */
+
+ priv->result = -ETIMEDOUT;
+
+ /* Then wake up the waiting thread */
+
+ sem_post(&priv->dmawait);
+}
+
+/****************************************************************************
+ * Name: qspi_dma_callback
+ *
+ * Description:
+ * This callback function is invoked at the completion of the QSPI DMA.
+ *
+ * Input Parameters:
+ * handle - The DMA handler
+ * isr - source of the DMA interrupt
+ * arg - A pointer to the chip select structure
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void qspi_dma_callback(DMA_HANDLE handle, uint8_t isr, void *arg)
+{
+ struct stm32l4_qspidev_s *priv = (struct stm32l4_qspidev_s *)arg;
+ DEBUGASSERT(priv != NULL);
+
+ /* Cancel the watchdog timeout */
+
+ (void)wd_cancel(priv->dmadog);
+
+ /* Sample DMA registers at the time of the callback */
+
+ qspi_dma_sample(priv, DMA_CALLBACK);
+
+ /* Report the result of the transfer only if the callback has not already
+ * reported an error.
+ */
+
+ if (priv->result == -EBUSY)
+ {
+ /* Save the result of the transfer if no error was previously reported */
+
+ if ( isr & DMA_CHAN_TCIF_BIT )
+ {
+ priv->result = OK;
+ }
+ else if ( isr & DMA_CHAN_TEIF_BIT )
+ {
+ priv->result = -EIO;
+ }
+ else
+ {
+ priv->result = OK;
+ }
+ }
+
+ /* Then wake up the waiting thread */
+
+ sem_post(&priv->dmawait);
+}
+
+/****************************************************************************
+ * Name: qspi_regaddr
+ *
+ * Description:
+ * Return the address of an QSPI register
+ *
+ ****************************************************************************/
+
+static inline uintptr_t qspi_regaddr(struct stm32l4_qspidev_s *priv,
+ unsigned int offset)
+{
+ return priv->base + offset;
+}
+
+/****************************************************************************
+ * Name: qspi_memory_dma
+ *
+ * Description:
+ * Perform one QSPI memory transfer using DMA
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ * meminfo - Describes the memory transfer to be performed.
+ * xctn - Describes the transaction context.
+ *
+ * Returned Value:
+ * Zero (OK) on SUCCESS, a negated errno on value of failure
+ *
+ ****************************************************************************/
+
+static int qspi_memory_dma(struct stm32l4_qspidev_s *priv,
+ struct qspi_meminfo_s *meminfo,
+ struct qspi_xctnspec_s *xctn)
+{
+ uint32_t dmaflags;
+ uint32_t regval;
+ int ret;
+
+ /* Initialize register sampling */
+
+ qspi_dma_sampleinit(priv);
+
+ /* Determine DMA flags and setup the DMA */
+
+ if (QSPIMEM_ISWRITE(meminfo->flags))
+ {
+ /* Setup the DMA (memory-to-peripheral) */
+
+ dmaflags = (QSPI_DMA_PRIO | DMA_CCR_MSIZE_8BITS | DMA_CCR_PSIZE_8BITS | DMA_CCR_MINC | DMA_CCR_DIR);
+ }
+ else
+ {
+ /* Setup the DMA (peripheral-to-memory) */
+
+ dmaflags = (QSPI_DMA_PRIO | DMA_CCR_MSIZE_8BITS | DMA_CCR_PSIZE_8BITS | DMA_CCR_MINC );
+ }
+
+ stm32l4_dmasetup(priv->dmach, qspi_regaddr(priv, STM32L4_QUADSPI_DR_OFFSET),
+ (uint32_t)meminfo->buffer, meminfo->buflen, dmaflags);
+
+ qspi_dma_sample(priv, DMA_AFTER_SETUP);
+
+ /* Enable the memory transfer */
+
+ regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET);
+ regval |= QSPI_CR_DMAEN;
+ qspi_putreg(priv, regval, STM32L4_QUADSPI_CR_OFFSET);
+
+ /* Set up the Communications Configuration Register as per command info */
+
+ qspi_ccrconfig(priv, xctn,
+ QSPIMEM_ISWRITE(meminfo->flags) ? CCR_FMODE_INDWR : CCR_FMODE_INDRD);
+
+ /* Start the DMA */
+
+ priv->result = -EBUSY;
+ stm32l4_dmastart(priv->dmach, qspi_dma_callback, priv, false);
+
+ qspi_dma_sample(priv, DMA_AFTER_START);
+
+ /* Wait for DMA completion. This is done in a loop because there may be
+ * false alarm semaphore counts that cause sem_wait() not fail to wait
+ * or to wake-up prematurely (for example due to the receipt of a signal).
+ * We know that the DMA has completed when the result is anything other
+ * that -EBUSY.
+ */
+
+ do
+ {
+ /* Start (or re-start) the watchdog timeout */
+
+ ret = wd_start(priv->dmadog, DMA_TIMEOUT_TICKS,
+ (wdentry_t)qspi_dma_timeout, 1, (uint32_t)priv);
+ if (ret != OK)
+ {
+ qspidbg("ERROR: wd_start failed: %d\n", ret);
+ }
+
+ /* Wait for the DMA complete */
+
+ ret = sem_wait(&priv->dmawait);
+
+ /* Cancel the watchdog timeout */
+
+ (void)wd_cancel(priv->dmadog);
+
+ /* Check if we were awakened by an error of some kind */
+
+ if (ret < 0)
+ {
+ /* EINTR is not a failure. That simply means that the wait
+ * was awakened by a signal.
+ */
+
+ int errorcode = errno;
+ if (errorcode != EINTR)
+ {
+ DEBUGPANIC();
+ regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET);
+ regval &= ~QSPI_CR_DMAEN;
+ qspi_putreg(priv, regval, STM32L4_QUADSPI_CR_OFFSET);
+ return -errorcode;
+ }
+ }
+
+ /* Note that we might be awakened before the wait is over due to
+ * residual counts on the semaphore. So, to handle, that case,
+ * we loop until something changes the DMA result to any value other
+ * than -EBUSY.
+ */
+ }
+ while (priv->result == -EBUSY);
+
+ /* Wait for Transfer complete, and not busy */
+
+ qspi_waitstatusflags(priv, QSPI_SR_TCF,1);
+ qspi_waitstatusflags(priv, QSPI_SR_BUSY,0);
+ MEMORY_SYNC();
+
+ /* Dump the sampled DMA registers */
+
+ qspi_dma_sampledone(priv);
+
+ /* Make sure that the DMA is stopped (it will be stopped automatically
+ * on normal transfers, but not necessarily when the transfer terminates
+ * on an error condition).
+ */
+
+ stm32l4_dmastop(priv->dmach);
+
+ regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET);
+ regval &= ~QSPI_CR_DMAEN;
+ qspi_putreg(priv, regval, STM32L4_QUADSPI_CR_OFFSET);
+
+ /* Complain if the DMA fails */
+
+ if (priv->result)
+ {
+ qspidbg("ERROR: DMA failed with result: %d\n", priv->result);
+ }
+
+ return priv->result;
+}
+#endif
+
+#if !defined(STM32L4_QSPI_INTERRUPTS)
/****************************************************************************
* Name: qspi_receive_blocking
*
@@ -1581,7 +1975,7 @@ static int qspi_command(struct qspi_dev_s *dev,
QSPI_FCR_CTEF | QSPI_FCR_CTCF | QSPI_FCR_CSMF | QSPI_FCR_CTOF,
STM32L4_QUADSPI_FCR);
-#ifdef QSPI_USE_INTERRUPTS
+#ifdef STM32L4_QSPI_INTERRUPTS
/* interrupt mode will need access to the transaction context */
priv->xctn = &xctn;
@@ -1665,9 +2059,9 @@ static int qspi_command(struct qspi_dev_s *dev,
ret = xctn.disposition;
-#elif defined(CONFIG_STM32L4_QSPI_DMA)
- /* XXX III dma mode (and 'autopolling'?) */
-
+ /* because command transfers are so small, we're not going to use
+ * DMA for them, only interrupts or polling
+ */
#else
/* Polling mode */
@@ -1762,7 +2156,7 @@ static int qspi_memory(struct qspi_dev_s *dev,
QSPI_FCR_CTEF | QSPI_FCR_CTCF | QSPI_FCR_CSMF | QSPI_FCR_CTOF,
STM32L4_QUADSPI_FCR);
-#ifdef QSPI_USE_INTERRUPTS
+#ifdef STM32L4_QSPI_INTERRUPTS
/* interrupt mode will need access to the transaction context */
priv->xctn = &xctn;
@@ -1824,8 +2218,46 @@ static int qspi_memory(struct qspi_dev_s *dev,
ret = xctn.disposition;
#elif defined(CONFIG_STM32L4_QSPI_DMA)
- /* XXX III dma mode (and 'autopolling'?) */
-
+ /* Can we perform DMA? Should we perform DMA? */
+
+ if (priv->candma &&
+ meminfo->buflen > CONFIG_STM32L4_QSPI_DMATHRESHOLD &&
+ IS_ALIGNED((uintptr_t)meminfo->buffer) &&
+ IS_ALIGNED(meminfo->buflen))
+ {
+ ret = qspi_memory_dma(priv, meminfo, &xctn);
+ }
+ else
+ {
+ /* polling mode */
+
+ /* Set up the Communications Configuration Register as per command info */
+
+ qspi_ccrconfig(priv, &xctn,
+ QSPIMEM_ISWRITE(meminfo->flags) ? CCR_FMODE_INDWR : CCR_FMODE_INDRD);
+
+ /* Transfer data */
+
+ DEBUGASSERT(meminfo->buffer != NULL && meminfo->buflen > 0);
+ DEBUGASSERT(IS_ALIGNED(meminfo->buffer));
+
+ if (QSPIMEM_ISWRITE(meminfo->flags))
+ {
+ ret = qspi_transmit_blocking(priv, &xctn);
+ }
+ else
+ {
+ ret = qspi_receive_blocking(priv, &xctn);
+ }
+
+ /* Wait for Transfer complete, and not busy */
+
+ qspi_waitstatusflags(priv, QSPI_SR_TCF,1);
+ qspi_waitstatusflags(priv, QSPI_SR_BUSY,0);
+
+ MEMORY_SYNC();
+ }
+
#else
/* polling mode */
@@ -1848,31 +2280,13 @@ static int qspi_memory(struct qspi_dev_s *dev,
ret = qspi_receive_blocking(priv, &xctn);
}
- MEMORY_SYNC();
-
-#if 0
-#ifdef CONFIG_STM32L4_QSPI_DMA
- /* Can we perform DMA? Should we perform DMA? */
-
- if (priv->candma &&
- meminfo->buflen > CONFIG_STM32L4_QSPI_DMATHRESHOLD &&
- IS_ALIGNED((uintptr_t)meminfo->buffer) &&
- IS_ALIGNED(meminfo->buflen))
- {
- return qspi_memory_dma(priv, meminfo);
- }
- else
-#endif
- {
- return qspi_memory_nodma(priv, meminfo);
- }
-#endif
-
/* Wait for Transfer complete, and not busy */
qspi_waitstatusflags(priv, QSPI_SR_TCF,1);
qspi_waitstatusflags(priv, QSPI_SR_BUSY,0);
+ MEMORY_SYNC();
+
#endif
return ret;
@@ -1949,7 +2363,7 @@ static int qspi_hw_initialize(struct stm32l4_qspidev_s *priv)
qspi_abort(priv);
- regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET);
+ regval = 0;
regval &= ~(QSPI_CR_EN);
qspi_putreg(priv, regval, STM32L4_QUADSPI_CR_OFFSET);
@@ -2099,10 +2513,35 @@ struct qspi_dev_s *stm32l4_qspi_initialize(int intf)
sem_init(&priv->exclsem, 0, 1);
#ifdef CONFIG_STM32L4_QSPI_DMA
- /* XXX III needs implementation */
+ /* Pre-allocate DMA channels. */
+
+ if (priv->candma)
+ {
+ priv->dmach = stm32l4_dmachannel(DMACHAN_QUADSPI);
+ if (!priv->dmach)
+ {
+ qspidbg("ERROR: Failed to allocate the DMA channel\n");
+ priv->candma = false;
+ }
+ }
+
+ /* Initialize the QSPI semaphore that is used to wake up the waiting
+ * thread when the DMA transfer completes.
+ */
+
+ sem_init(&priv->dmawait, 0, 0);
+
+ /* Create a watchdog time to catch DMA timeouts */
+
+ priv->dmadog = wd_create();
+ if (priv->dmadog == NULL)
+ {
+ qspidbg("ERROR: Failed to create wdog\n");
+ goto errout_with_dmahandles;
+ }
#endif
-#ifdef QSPI_USE_INTERRUPTS
+#ifdef STM32L4_QSPI_INTERRUPTS
/* Attach the interrupt handler */
ret = irq_attach(priv->irq, priv->handler);
@@ -2133,7 +2572,7 @@ struct qspi_dev_s *stm32l4_qspi_initialize(int intf)
priv->initialized = true;
priv->memmap = false;
-#ifdef QSPI_USE_INTERRUPTS
+#ifdef STM32L4_QSPI_INTERRUPTS
up_enable_irq(priv->irq);
#endif
}
@@ -2141,13 +2580,22 @@ struct qspi_dev_s *stm32l4_qspi_initialize(int intf)
return &priv->qspi;
errout_with_irq:
-#ifdef QSPI_USE_INTERRUPTS
+#ifdef STM32L4_QSPI_INTERRUPTS
irq_detach(priv->irq);
errout_with_dmadog:
#endif
#ifdef CONFIG_STM32L4_QSPI_DMA
- /* XXX III needs implementation */
+ wd_delete(priv->dmadog);
+
+errout_with_dmahandles:
+ sem_destroy(&priv->dmawait);
+
+ if (priv->dmach)
+ {
+ stm32l4_dmafree(priv->dmach);
+ priv->dmach = NULL;
+ }
#endif
sem_destroy(&priv->exclsem);
@@ -2209,7 +2657,7 @@ void stm32l4_qspi_enter_memorymapped(struct qspi_dev_s* dev,
qspi_putreg(&g_qspi0dev, QSPI_FCR_CTOF, STM32L4_QUADSPI_FCR);
-#ifdef QSPI_USE_INTERRUPTS
+#ifdef STM32L4_QSPI_INTERRUPTS
/* Enable Timeout interrupt */
regval = qspi_getreg(priv, STM32L4_QUADSPI_CR_OFFSET);
@@ -2227,7 +2675,10 @@ void stm32l4_qspi_enter_memorymapped(struct qspi_dev_s* dev,
/* create a transaction object */
qspi_setupxctnfrommem(&xctn, meminfo);
+
+#ifdef STM32L4_QSPI_INTERRUPTS
priv->xctn = NULL;
+#endif
/* set it into the ccr */
diff --git a/arch/arm/src/stm32l4/stm32l4_start.c b/arch/arm/src/stm32l4/stm32l4_start.c
index ee1f894d8d..6209cde541 100644
--- a/arch/arm/src/stm32l4/stm32l4_start.c
+++ b/arch/arm/src/stm32l4/stm32l4_start.c
@@ -79,6 +79,8 @@
* 0x2001:7fff - End of internal SRAM and end of heap
*/
+#define SRAM2_START 0x10000000
+#define SRAM2_END 0x10008000
#define IDLE_STACK ((uintptr_t)&_ebss+CONFIG_IDLETHREAD_STACKSIZE-4)
#define HEAP_BASE ((uintptr_t)&_ebss+CONFIG_IDLETHREAD_STACKSIZE)
@@ -287,6 +289,24 @@ void __start(void)
__asm__ volatile ("sub r10, sp, %0" : : "r" (CONFIG_IDLETHREAD_STACKSIZE - 64) : );
#endif
+#ifdef CONFIG_STM32L4_SRAM2_INIT
+ /* The SRAM2 region is parity checked, but upon power up, it will be in
+ * a random state and probably invalid with respect to parity, potentially
+ * generating faults if accessed. If elected, we will write zeros to the
+ * memory, forcing the parity to be set to a valid state.
+ * NOTE: this is optional because this may be inappropriate, especially
+ * if the memory is being used for it's battery backed purpose. In that
+ * case, the first-time initialization needs to be performed by the board
+ * under application-specific circumstances. On the other hand, if we're
+ * using this memory for, say, additional heap space, then this is handy.
+ */
+
+ for (dest = (uint32_t *)SRAM2_START; dest < (uint32_t *)SRAM2_END; )
+ {
+ *dest++ = 0;
+ }
+#endif
+
/* Configure the UART so that we can get debug output as soon as possible */
stm32l4_clockconfig();
diff --git a/arch/arm/src/stm32l4/stm32l4x6xx_dma.c b/arch/arm/src/stm32l4/stm32l4x6xx_dma.c
index 2e6afa2b3b..eb91e3a754 100644
--- a/arch/arm/src/stm32l4/stm32l4x6xx_dma.c
+++ b/arch/arm/src/stm32l4/stm32l4x6xx_dma.c
@@ -3,6 +3,8 @@
*
* Copyright (C) 2009, 2011-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
+ * Sebastien Lorquet
+ * dev@ziggurat29.com
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -306,16 +308,17 @@ static int stm32l4_dmainterrupt(int irq, void *context)
isr = dmabase_getreg(dmach, STM32L4_DMA_ISR_OFFSET) & DMA_ISR_CHAN_MASK(dmach->chan);
- /* Clear the interrupts we are handling */
-
- dmabase_putreg(dmach, STM32L4_DMA_IFCR_OFFSET, isr);
-
/* Invoke the callback */
if (dmach->callback)
{
dmach->callback(dmach, isr >> DMA_ISR_CHAN_SHIFT(dmach->chan), dmach->arg);
}
+
+ /* Clear the interrupts we are handling */
+
+ dmabase_putreg(dmach, STM32L4_DMA_IFCR_OFFSET, isr);
+
return OK;
}
@@ -387,9 +390,9 @@ void weak_function up_dmainitialize(void)
* version. Feel free to do that if that is what you need.
*
* Input parameter:
- * chndx - Identifies the stream/channel resource. For the STM32 F1, this
- * is simply the channel number as provided by the DMACHAN_* definitions
- * in chip/stm32f10xxx_dma.h.
+ * chan - Identifies the stream/channel resource
+ * This is a bit encoded value as provided by the DMACHAN_* definitions
+ * in chip/stm32l4x6xx_dma.h
*
* Returned Value:
* Provided that 'chndx' is valid, this function ALWAYS returns a non-NULL,
@@ -471,6 +474,9 @@ void stm32l4_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
struct stm32l4_dma_s *dmach = (struct stm32l4_dma_s *)handle;
uint32_t regval;
+ DEBUGASSERT(handle != NULL);
+ DEBUGASSERT(ntransfers<65536);
+
/* Then DMA_CNDTRx register can only be modified if the DMA channel is
* disabled.
*/
@@ -514,7 +520,12 @@ void stm32l4_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
regval |= ccr;
dmachan_putreg(dmach, STM32L4_DMACHAN_CCR_OFFSET, regval);
-#warning TODO define peripheral by using dmach->function
+ /* define peripheral indicated in dmach->function */
+
+ regval = dmabase_getreg(dmach, STM32L4_DMA_CSELR_OFFSET);
+ regval &= ~(0x0f << (dmach->chan << 2));
+ regval |= (dmach->function << (dmach->chan << 2));
+ dmabase_putreg(dmach, STM32L4_DMA_CSELR_OFFSET, regval);
}
/****************************************************************************
@@ -641,7 +652,9 @@ bool stm32l4_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr)
* Transfers to/from memory performed by the DMA controller are
* required to be aligned to their size.
*
- * See ST RM0090 rev4, section 9.3.11
+ * Datasheet 3.13 claims
+ * "Access to Flash, SRAM, APB and AHB peripherals as source
+ * and destination"
*
* Compute mend inline to avoid a possible non-constant integer
* multiply.
@@ -682,13 +695,14 @@ bool stm32l4_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr)
switch (maddr & STM32L4_REGION_MASK)
{
-#if defined(CONFIG_STM32L4_STM32F10XX)
+ case STM32L4_PERIPH_BASE:
+ case STM32L4_FSMC_BASE:
case STM32L4_FSMC_BANK1:
case STM32L4_FSMC_BANK2:
case STM32L4_FSMC_BANK3:
case STM32L4_FSMC_BANK4:
-#endif
case STM32L4_SRAM_BASE:
+ case STM32L4_SRAM2_BASE:
case STM32L4_CODE_BASE:
/* All RAM and flash is supported */
@@ -719,13 +733,14 @@ void stm32l4_dmasample(DMA_HANDLE handle, struct stm32l4_dmaregs_s *regs)
struct stm32l4_dma_s *dmach = (struct stm32l4_dma_s *)handle;
irqstate_t flags;
- flags = irqsave();
+ flags = enter_critical_section();
regs->isr = dmabase_getreg(dmach, STM32L4_DMA_ISR_OFFSET);
+ regs->cselr = dmabase_getreg(dmach, STM32L4_DMA_CSELR_OFFSET);
regs->ccr = dmachan_getreg(dmach, STM32L4_DMACHAN_CCR_OFFSET);
regs->cndtr = dmachan_getreg(dmach, STM32L4_DMACHAN_CNDTR_OFFSET);
regs->cpar = dmachan_getreg(dmach, STM32L4_DMACHAN_CPAR_OFFSET);
regs->cmar = dmachan_getreg(dmach, STM32L4_DMACHAN_CMAR_OFFSET);
- irqrestore(flags);
+ leave_critical_section(flags);
}
#endif
@@ -748,7 +763,8 @@ void stm32l4_dmadump(DMA_HANDLE handle, const struct stm32l4_dmaregs_s *regs,
uint32_t dmabase = DMA_BASE(dmach->base);
dmadbg("DMA Registers: %s\n", msg);
- dmadbg(" ISRC[%08x]: %08x\n", dmabase + STM32L4_DMA_ISR_OFFSET, regs->isr);
+ dmadbg(" ISR[%08x]: %08x\n", dmabase + STM32L4_DMA_ISR_OFFSET, regs->isr);
+ dmadbg(" CSELR[%08x]: %08x\n", dmabase + STM32L4_DMA_CSELR_OFFSET, regs->cselr);
dmadbg(" CCR[%08x]: %08x\n", dmach->base + STM32L4_DMACHAN_CCR_OFFSET, regs->ccr);
dmadbg(" CNDTR[%08x]: %08x\n", dmach->base + STM32L4_DMACHAN_CNDTR_OFFSET, regs->cndtr);
dmadbg(" CPAR[%08x]: %08x\n", dmach->base + STM32L4_DMACHAN_CPAR_OFFSET, regs->cpar);
diff --git a/configs/stm32l476vg-disco/include/board.h b/configs/stm32l476vg-disco/include/board.h
index dcf8bf6bdc..c3e1efd354 100644
--- a/configs/stm32l476vg-disco/include/board.h
+++ b/configs/stm32l476vg-disco/include/board.h
@@ -144,16 +144,6 @@
#define GPIO_QSPI_IO3 (GPIO_QSPI_BK1_IO3_2 | GPIO_FLOAT | GPIO_PUSHPULL | GPIO_SPEED_100MHz)
#define GPIO_QSPI_SCK (GPIO_QSPI_CLK_2 | GPIO_FLOAT | GPIO_PUSHPULL | GPIO_SPEED_100MHz)
-#if 0
-/* XXX hmm, elsewhere */
-
-#define QSPI_USE_INTERRUPTS 1
-
-/* XXX hmm, better? (2^(23+1)); this is the value that goes into FSIZE */
-
-#define QSPI_FLASH_SIZE 23
-#endif
-
/* SPI */
/* XXX is SPI1 used on Disco? */
diff --git a/configs/stm32l476vg-disco/nsh/defconfig b/configs/stm32l476vg-disco/nsh/defconfig
index 8ee16e46cb..43178e9ec5 100644
--- a/configs/stm32l476vg-disco/nsh/defconfig
+++ b/configs/stm32l476vg-disco/nsh/defconfig
@@ -59,6 +59,7 @@ CONFIG_DEBUG_VERBOSE=y
#
# OS Function Debug Options
#
+# CONFIG_DEBUG_DMA is not set
# CONFIG_DEBUG_HEAP is not set
# CONFIG_DEBUG_IRQ is not set
@@ -176,6 +177,7 @@ CONFIG_ARMV7M_HAVE_STACKCHECK=y
# CONFIG_ARMV7M_ITMSYSLOG is not set
# CONFIG_SERIAL_TERMIOS is not set
# CONFIG_USART2_RS485 is not set
+# CONFIG_USART2_RXDMA is not set
# CONFIG_SERIAL_DISABLE_REORDERING is not set
#
@@ -197,7 +199,7 @@ CONFIG_STM32L4_FLASH_1024KB=y
# CONFIG_STM32L4_ADC is not set
# CONFIG_STM32L4_CAN is not set
# CONFIG_STM32L4_DAC is not set
-# CONFIG_STM32L4_DMA is not set
+CONFIG_STM32L4_DMA=y
# CONFIG_STM32L4_I2C is not set
# CONFIG_STM32L4_SAI is not set
# CONFIG_STM32L4_SPI is not set
@@ -207,8 +209,8 @@ CONFIG_STM32L4_USART=y
#
# AHB1 Peripherals
#
-# CONFIG_STM32L4_DMA1 is not set
-# CONFIG_STM32L4_DMA2 is not set
+CONFIG_STM32L4_DMA1=y
+CONFIG_STM32L4_DMA2=y
# CONFIG_STM32L4_CRC is not set
# CONFIG_STM32L4_TSC is not set
@@ -230,6 +232,17 @@ CONFIG_STM32L4_QSPI=y
CONFIG_STM32L4_QSPI_FLASH_SIZE=16777216
CONFIG_STM32L4_QSPI_FIFO_THESHOLD=4
CONFIG_STM32L4_QSPI_CSHT=1
+# CONFIG_STM32L4_QSPI_POLLING is not set
+# CONFIG_STM32L4_QSPI_INTERRUPTS is not set
+CONFIG_STM32L4_QSPI_DMA=y
+CONFIG_STM32L4_QSPI_DMA_CHAN_1_5=y
+# CONFIG_STM32L4_QSPI_DMA_CHAN_2_7 is not set
+# CONFIG_STM32L4_QSPI_DMAPRIORITY_VERYHIGH is not set
+# CONFIG_STM32L4_QSPI_DMAPRIORITY_HIGH is not set
+CONFIG_STM32L4_QSPI_DMAPRIORITY_MEDIUM=y
+# CONFIG_STM32L4_QSPI_DMAPRIORITY_LOW is not set
+CONFIG_STM32L4_QSPI_DMATHRESHOLD=4
+# CONFIG_STM32L4_QSPI_REGDEBUG is not set
#
# APB1 Peripherals
@@ -302,7 +315,7 @@ CONFIG_STM32L4_SAI1PLL=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_HAVE_IRQPRIO=y
# CONFIG_ARCH_L2CACHE is not set
# CONFIG_ARCH_HAVE_COHERENT_DCACHE is not set
@@ -384,7 +397,7 @@ CONFIG_LIB_BOARDCTL=y
# CONFIG_BOARDCTL_ADCTEST is not set
# CONFIG_BOARDCTL_PWMTEST is not set
# CONFIG_BOARDCTL_GRAPHICS is not set
-# CONFIG_BOARDCTL_IOCTL is not set
+CONFIG_BOARDCTL_IOCTL=y
#
# RTOS Features
@@ -646,12 +659,7 @@ CONFIG_USART2_2STOP=0
#
# System Logging
#
-CONFIG_RAMLOG=y
-CONFIG_RAMLOG_SYSLOG=y
-# CONFIG_RAMLOG_CONSOLE is not set
-CONFIG_RAMLOG_BUFSIZE=8192
-# CONFIG_RAMLOG_CRLF is not set
-CONFIG_RAMLOG_NONBLOCKING=y
+# CONFIG_RAMLOG is not set
# CONFIG_SYSLOG_CONSOLE is not set
#
@@ -708,9 +716,8 @@ CONFIG_FS_PROCFS_REGISTER=y
#
# System Logging
#
-CONFIG_SYSLOG=y
+# CONFIG_SYSLOG is not set
# CONFIG_SYSLOG_TIMESTAMP is not set
-# CONFIG_SYSLOG_CHAR is not set
#
# Graphics Support
@@ -838,14 +845,7 @@ CONFIG_EXAMPLES_BUTTONS_NAME7="Button 7"
# CONFIG_EXAMPLES_CXXTEST is not set
# CONFIG_EXAMPLES_DHCPD is not set
# CONFIG_EXAMPLES_ELF is not set
-CONFIG_EXAMPLES_FSTEST=y
-CONFIG_EXAMPLES_FSTEST_MAXNAME=32
-CONFIG_EXAMPLES_FSTEST_MAXFILE=8192
-CONFIG_EXAMPLES_FSTEST_MAXIO=347
-CONFIG_EXAMPLES_FSTEST_MAXOPEN=512
-CONFIG_EXAMPLES_FSTEST_MOUNTPT="/mnt/n25qxxx"
-CONFIG_EXAMPLES_FSTEST_NLOOPS=1
-CONFIG_EXAMPLES_FSTEST_VERBOSE=y
+# CONFIG_EXAMPLES_FSTEST is not set
# CONFIG_EXAMPLES_FTPC is not set
# CONFIG_EXAMPLES_FTPD is not set
# CONFIG_EXAMPLES_HELLO is not set
@@ -871,20 +871,12 @@ CONFIG_EXAMPLES_NSH_CXXINITIALIZE=y
# CONFIG_EXAMPLES_NXIMAGE is not set
# CONFIG_EXAMPLES_NXLINES is not set
# CONFIG_EXAMPLES_NXTEXT is not set
-CONFIG_EXAMPLES_OSTEST=y
-CONFIG_EXAMPLES_OSTEST_LOOPS=1
-CONFIG_EXAMPLES_OSTEST_STACKSIZE=8192
-CONFIG_EXAMPLES_OSTEST_NBARRIER_THREADS=8
-CONFIG_EXAMPLES_OSTEST_RR_RANGE=10000
-CONFIG_EXAMPLES_OSTEST_RR_RUNS=10
-CONFIG_EXAMPLES_OSTEST_WAITRESULT=y
+# CONFIG_EXAMPLES_OSTEST is not set
# CONFIG_EXAMPLES_PCA9635 is not set
# CONFIG_EXAMPLES_PIPE is not set
# CONFIG_EXAMPLES_PPPD is not set
# CONFIG_EXAMPLES_POSIXSPAWN is not set
-CONFIG_EXAMPLES_RANDOM=y
-CONFIG_EXAMPLES_MAXSAMPLES=64
-CONFIG_EXAMPLES_NSAMPLES=8
+# CONFIG_EXAMPLES_RANDOM is not set
# CONFIG_EXAMPLES_RGBLED is not set
# CONFIG_EXAMPLES_RGMP is not set
# CONFIG_EXAMPLES_SENDMAIL is not set
diff --git a/configs/stm32l476vg-disco/src/stm32_appinit.c b/configs/stm32l476vg-disco/src/stm32_appinit.c
index 71da004099..5e277507ec 100644
--- a/configs/stm32l476vg-disco/src/stm32_appinit.c
+++ b/configs/stm32l476vg-disco/src/stm32_appinit.c
@@ -45,6 +45,8 @@
#include
#include
#include
+#include
+#include
#include
#include
@@ -57,6 +59,7 @@
#include
#include
#include
+#include
#include
#include
@@ -193,6 +196,7 @@ int board_app_initialize(void)
#ifdef HAVE_N25QXXX_SMARTFS
/* Configure the device with no partition support */
+ SYSLOG("doing smart_initialize()\n");
ret = smart_initialize(N25QXXX_SMART_MINOR, mtd, NULL);
if (ret != OK)
{
@@ -202,6 +206,7 @@ int board_app_initialize(void)
#elif defined(HAVE_N25QXXX_NXFFS)
/* Initialize to provide NXFFS on the N25QXXX MTD interface */
+ SYSLOG("doing nxffs_initialize()\n");
ret = nxffs_initialize(mtd);
if (ret < 0)
{
@@ -237,9 +242,9 @@ int board_app_initialize(void)
/* NOTE: for this to work, you will need to make sure that
* CONFIG_FS_WRITABLE is set in the config. It's not a user-
* visible setting, but you can make it set by selecting an
- * arbitrary writeable file system (you don't have to actually
+ * arbitrary writable file system (you don't have to actually
* use it, just select it so that the block device created via
- * ftl_initialize() will be writeable). Personally, I chose FAT,
+ * ftl_initialize() will be writable). Personally, I chose FAT,
* because SMARTFS and NXFFS will cause the other code branches
* above to become active.
*/
@@ -257,3 +262,12 @@ int board_app_initialize(void)
return OK;
}
#endif /* CONFIG_LIB_BOARDCTL */
+
+
+
+#ifdef CONFIG_BOARDCTL_IOCTL
+int board_ioctl(unsigned int cmd, uintptr_t arg)
+{
+ return OK;
+}
+#endif