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