diff --git a/AGENTS.md b/AGENTS.md index b2c077191d5..ab9ab5fd6cb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -86,7 +86,7 @@ INAV uses special memory attributes for performance-critical code on resource-co ```c FASTRAM // Fast RAM section (aligned) EXTENDED_FASTRAM // Extended fast RAM (STM32F4/F7 only) -DMA_RAM // DMA-accessible RAM (STM32H7, AT32F43x) +DMA_RAM // DMA-accessible RAM, not cached on F7/H7 (STM32F7, STM32H7, AT32F43x) SLOW_RAM // Slower external RAM - deprecated, o not use STATIC_FASTRAM // Static variable in fast RAM STATIC_FASTRAM_UNIT_TESTED // Static fast RAM variable visible in unit tests diff --git a/cmake/stm32f7.cmake b/cmake/stm32f7.cmake index d8f52de333f..a0da095fc51 100644 --- a/cmake/stm32f7.cmake +++ b/cmake/stm32f7.cmake @@ -75,6 +75,9 @@ main_sources(STM32F7_SRC drivers/timer_impl_hal.c drivers/timer_stm32f7xx.c drivers/system_stm32f7xx.c + drivers/memprot.h + drivers/memprot_hal.c + drivers/memprot_stm32f7xx.c drivers/serial_uart_stm32f7xx.c drivers/serial_uart_hal.c drivers/sdcard/sdmmc_sdio_hal.c @@ -91,6 +94,7 @@ set(STM32F7_DEFINITIONS ${CORTEX_M7_DEFINITIONS} USE_HAL_DRIVER USE_FULL_LL_DRIVER + MAX_MPU_REGIONS=8 ) function(target_stm32f7xx) diff --git a/src/main/build/build_config.h b/src/main/build/build_config.h index 75bb46668d7..959267fc2d2 100644 --- a/src/main/build/build_config.h +++ b/src/main/build/build_config.h @@ -57,6 +57,10 @@ #elif defined (AT32F43x) #define DMA_RAM __attribute__ ((section(".DMA_RAM"))) #define SLOW_RAM __attribute__ ((section(".SLOW_RAM"))) +#elif defined (STM32F7) +#define DMA_RAM __attribute__ ((section(".DMA_RAM"))) +#define DMA_RAM_UNCACHED // the UART receive rings move here only then +#define SLOW_RAM #else #define DMA_RAM #define SLOW_RAM diff --git a/src/main/config/config_streamer_stm32f7.c b/src/main/config/config_streamer_stm32f7.c index 61b148fce57..867e86972a0 100644 --- a/src/main/config/config_streamer_stm32f7.c +++ b/src/main/config/config_streamer_stm32f7.c @@ -106,6 +106,8 @@ void config_streamer_impl_unlock(void) void config_streamer_impl_lock(void) { HAL_FLASH_Lock(); + // The D-cache keeps lines from before the erase, and erratum 1259864 can serve stale write-through data + SCB_InvalidateDCache_by_Addr((uint32_t *)&__config_start, &__config_end - &__config_start); } int config_streamer_impl_write_word(config_streamer_t *c, config_streamer_buffer_align_type_t *buffer) diff --git a/src/main/drivers/adc_impl.h b/src/main/drivers/adc_impl.h index 32f4414e83f..146d65e404c 100644 --- a/src/main/drivers/adc_impl.h +++ b/src/main/drivers/adc_impl.h @@ -28,7 +28,7 @@ #define ADC_TAG_MAP_COUNT 10 #endif -#if defined(STM32H7) +#if defined(STM32H7) || defined(STM32F7) #define ADC_VALUES_ALIGNMENT(def) DMA_RAM def __attribute__ ((aligned (32))) #else #define ADC_VALUES_ALIGNMENT(def) def diff --git a/src/main/drivers/adc_stm32f7xx.c b/src/main/drivers/adc_stm32f7xx.c index 4b5aae88384..a18dd6f4289 100644 --- a/src/main/drivers/adc_stm32f7xx.c +++ b/src/main/drivers/adc_stm32f7xx.c @@ -83,6 +83,9 @@ static void adcInstanceInit(ADCDevice adcDevice) { adcDevice_t * adc = &adcHardware[adcDevice]; + // DMA_RAM is not zeroed at startup: read 0, not leftovers, if the DMA never starts + memset((void *)adcValues[adcDevice], 0, sizeof(adcValues[adcDevice])); + RCC_ClockCmd(adc->rccDMA, ENABLE); RCC_ClockCmd(adc->rccADC, ENABLE); diff --git a/src/main/drivers/memprot_stm32f7xx.c b/src/main/drivers/memprot_stm32f7xx.c new file mode 100644 index 00000000000..5dfb4eec0ca --- /dev/null +++ b/src/main/drivers/memprot_stm32f7xx.c @@ -0,0 +1,50 @@ +/* + * This file is part of Cleanflight and Betaflight. + * + * Cleanflight and Betaflight are free software. You can redistribute + * this software and/or modify this software under the terms of the + * GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * Cleanflight and Betaflight are distributed in the hope that they + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software. + * + * If not, see . + */ + +#include "platform.h" + +#include "common/utils.h" + +#include "memprot.h" + +#ifndef BOOTLOADER + +// Defined in linker script +extern uint8_t dmaram_start; + +mpuRegion_t mpuRegions[] = { + { + // The whole 16 KB SRAM2 bank, where DMA_RAM is the only section: shareable, which the Cortex-M7 does not cache + .start = (uint32_t)&dmaram_start, + .end = 0, + .size = MPU_REGION_SIZE_16KB, + .perm = MPU_REGION_FULL_ACCESS, + .exec = MPU_INSTRUCTION_ACCESS_ENABLE, + .shareable = MPU_ACCESS_SHAREABLE, + .cacheable = MPU_ACCESS_CACHEABLE, + .bufferable = MPU_ACCESS_NOT_BUFFERABLE, + }, +}; + +unsigned mpuRegionCount = ARRAYLEN(mpuRegions); + +STATIC_ASSERT(ARRAYLEN(mpuRegions) <= MAX_MPU_REGIONS, MPU_region_count_exceeds_limit); + +#endif diff --git a/src/main/drivers/pwm_output.c b/src/main/drivers/pwm_output.c index 20aed6c7264..17136b26a36 100644 --- a/src/main/drivers/pwm_output.c +++ b/src/main/drivers/pwm_output.c @@ -91,7 +91,7 @@ typedef void (*pwmWriteFuncPtr)(uint8_t index, uint16_t value); // function pointer used to write motors #ifdef USE_DSHOT_DMAR - timerDMASafeType_t dmaBurstBuffer[MAX_DMA_TIMERS][DSHOT_DMA_BUFFER_SIZE * 4]; +static DMA_RAM timerDMASafeType_t dmaBurstBuffer[MAX_DMA_TIMERS][DSHOT_DMA_BUFFER_SIZE * 4]; #endif #ifdef USE_DSHOT @@ -437,6 +437,10 @@ static pwmOutputPort_t * motorConfigDshot(const timerHardware_t * timerHardware, return NULL; } + // DMA_RAM is NOLOAD: a channel of this timer that drives no motor must read zero, not leftovers + if (!burstDmaTimers[burstDmaTimerIndex].dmaBurstBuffer) { + ZERO_FARRAY(dmaBurstBuffer[burstDmaTimerIndex]); + } port->dmaBurstBuffer = &dmaBurstBuffer[burstDmaTimerIndex][0]; burstDmaTimer_t *burstDmaTimer = &burstDmaTimers[burstDmaTimerIndex]; burstDmaTimer->dmaBurstBuffer = port->dmaBurstBuffer; diff --git a/src/main/drivers/sdcard/sdcard_sdio.c b/src/main/drivers/sdcard/sdcard_sdio.c index f76377550a7..78838c976cc 100644 --- a/src/main/drivers/sdcard/sdcard_sdio.c +++ b/src/main/drivers/sdcard/sdcard_sdio.c @@ -54,7 +54,7 @@ #if defined(USE_SDCARD_SDIO_CACHE) // Use this to speed up writing to SDCARD... asyncfatfs has limited support for multiblock write #define FATFS_BLOCK_CACHE_SIZE 16 -uint8_t writeCache[512 * FATFS_BLOCK_CACHE_SIZE] __attribute__ ((aligned (4))); +uint8_t writeCache[512 * FATFS_BLOCK_CACHE_SIZE] __attribute__ ((aligned (32))); // SDIO DMA with the D-cache uint32_t cacheCount = 0; void cache_write(uint8_t *buffer) diff --git a/src/main/drivers/sdcard/sdmmc_sdio_hal.c b/src/main/drivers/sdcard/sdmmc_sdio_hal.c index 23b9c34678c..f9ec8c88bee 100644 --- a/src/main/drivers/sdcard/sdmmc_sdio_hal.c +++ b/src/main/drivers/sdcard/sdmmc_sdio_hal.c @@ -600,17 +600,14 @@ SD_Error_t SD_CheckRead(void) { SD_Error_t SD_WriteBlocks_DMA(uint64_t WriteAddress, uint32_t *buffer, uint32_t BlockSize, uint32_t NumberOfBlocks) { SD_Error_t ErrorState = SD_OK; - SD_Handle.TXCplt = 1; if (BlockSize != 512) { return SD_ERROR; // unsupported. } -#ifndef STM32F7 if ((uint32_t)buffer & 0x1f) { return SD_ADDR_MISALIGNED; } -#endif // Ensure the data is flushed to main memory SCB_CleanDCache_by_Addr(buffer, NumberOfBlocks * BlockSize); @@ -623,7 +620,10 @@ SD_Error_t SD_WriteBlocks_DMA(uint64_t WriteAddress, uint32_t *buffer, uint32_t } } #endif + // Busy only once a transfer really starts: a rejected write must not leave the card reported busy + SD_Handle.TXCplt = 1; if (HAL_SD_WriteBlocks_DMA(&hsd, (uint8_t *)buffer, WriteAddress, NumberOfBlocks) != HAL_OK) { + SD_Handle.TXCplt = 0; return SD_ERROR; } @@ -646,11 +646,9 @@ SD_Error_t SD_ReadBlocks_DMA(uint64_t ReadAddress, uint32_t *buffer, uint32_t Bl return SD_ERROR; // unsupported. } -#ifndef STM32F7 if ((uint32_t)buffer & 0x1f) { return SD_ADDR_MISALIGNED; } -#endif SD_Handle.RXCplt = 1; @@ -658,6 +656,9 @@ SD_Error_t SD_ReadBlocks_DMA(uint64_t ReadAddress, uint32_t *buffer, uint32_t Bl sdReadParameters.BlockSize = BlockSize; sdReadParameters.NumberOfBlocks = NumberOfBlocks; + // A dirty line evicted during the transfer would overwrite what the DMA wrote + SCB_InvalidateDCache_by_Addr(buffer, NumberOfBlocks * BlockSize); + #ifdef STM32F7 if (sd_dma.Init.Direction != DMA_PERIPH_TO_MEMORY) { sd_dma.Init.Direction = DMA_PERIPH_TO_MEMORY; diff --git a/src/main/io/asyncfatfs/asyncfatfs.c b/src/main/io/asyncfatfs/asyncfatfs.c index cfa7da71ae8..57ec1cccad7 100644 --- a/src/main/io/asyncfatfs/asyncfatfs.c +++ b/src/main/io/asyncfatfs/asyncfatfs.c @@ -437,7 +437,7 @@ typedef struct afatfs_t { } initState; #endif -#ifdef STM32H7 +#if defined(STM32H7) || defined(STM32F7) uint8_t *cache; #else uint8_t cache[AFATFS_SECTOR_SIZE * AFATFS_NUM_CACHE_SECTORS]; @@ -487,7 +487,8 @@ typedef struct afatfs_t { uint32_t rootDirectorySectors; // Zero on FAT32, for FAT16 the number of sectors that the root directory occupies } afatfs_t; -#ifdef STM32H7 +#if defined(STM32H7) || defined(STM32F7) +// SD DMA with the D-cache on: cache maintenance works on whole 32-byte lines static uint8_t afatfs_cache[AFATFS_SECTOR_SIZE * AFATFS_NUM_CACHE_SECTORS] __attribute__((aligned(32))); #endif @@ -3675,7 +3676,7 @@ bool afatfs_isCurrentDirRoot(void) void afatfs_init(void) { -#ifdef STM32H7 +#if defined(STM32H7) || defined(STM32F7) afatfs.cache = afatfs_cache; #endif afatfs.filesystemState = AFATFS_FILESYSTEM_STATE_INITIALIZATION; diff --git a/src/main/msc/usbd_storage_sd_spi.c b/src/main/msc/usbd_storage_sd_spi.c index 26a38e00b6a..d6c50caf19f 100644 --- a/src/main/msc/usbd_storage_sd_spi.c +++ b/src/main/msc/usbd_storage_sd_spi.c @@ -58,9 +58,9 @@ #define STORAGE_BLK_NBR 0x10000 #define STORAGE_BLK_SIZ 0x200 -// H7 SDIO DMA requires 32-byte aligned buffers +// SDIO DMA with the D-cache on (F7, H7) requires 32-byte aligned buffers // USB MSC bot_data buffer is only 16-byte aligned, so we need an intermediate buffer -#if defined(STM32H7) && defined(USE_SDCARD_SDIO) +#if (defined(STM32H7) || defined(STM32F7)) && defined(USE_SDCARD_SDIO) __attribute__((aligned(32))) static uint8_t alignedBuffer[512]; #endif @@ -233,8 +233,8 @@ static int8_t STORAGE_Read (uint8_t lun, LED1_ON; for (int i = 0; i < blk_len; i++) { uint32_t timeout; -#if defined(STM32H7) && defined(USE_SDCARD_SDIO) - // H7 SDIO DMA requires 32-byte aligned buffers +#if (defined(STM32H7) || defined(STM32F7)) && defined(USE_SDCARD_SDIO) + // SDIO DMA requires 32-byte aligned buffers // USB MSC buffer may not be aligned, so use intermediate buffer timeout = 0; while (sdcard_readBlock(blk_addr + i, alignedBuffer, NULL, 0) == 0) { @@ -293,8 +293,8 @@ static int8_t STORAGE_Write (uint8_t lun, LED1_ON; for (int i = 0; i < blk_len; i++) { uint32_t timeout; -#if defined(STM32H7) && defined(USE_SDCARD_SDIO) - // H7 SDIO DMA requires 32-byte aligned buffers +#if (defined(STM32H7) || defined(STM32F7)) && defined(USE_SDCARD_SDIO) + // SDIO DMA requires 32-byte aligned buffers // USB MSC buffer may not be aligned, so use intermediate buffer memcpy(alignedBuffer, buf + (i * 512), 512); timeout = 0; diff --git a/src/main/target/link/stm32_flash_f722xe.ld b/src/main/target/link/stm32_flash_f722xe.ld index 3a9094ed81f..739b24056a5 100644 --- a/src/main/target/link/stm32_flash_f722xe.ld +++ b/src/main/target/link/stm32_flash_f722xe.ld @@ -38,11 +38,13 @@ MEMORY FLASH1 (rx) : ORIGIN = 0x08008000, LENGTH = 480K TCM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K - RAM (rwx) : ORIGIN = 0x20010000, LENGTH = 192K + RAM (rwx) : ORIGIN = 0x20010000, LENGTH = 176K + SRAM2 (rwx) : ORIGIN = 0x2003C000, LENGTH = 16K MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K } REGION_ALIAS("STACKRAM", TCM) REGION_ALIAS("FASTRAM", TCM) +REGION_ALIAS("DMARAM", SRAM2) INCLUDE "stm32_flash_f7_split.ld" diff --git a/src/main/target/link/stm32_flash_f722xe_for_bl.ld b/src/main/target/link/stm32_flash_f722xe_for_bl.ld index 83c9a43fc5e..581c5d34015 100644 --- a/src/main/target/link/stm32_flash_f722xe_for_bl.ld +++ b/src/main/target/link/stm32_flash_f722xe_for_bl.ld @@ -38,12 +38,14 @@ MEMORY FLASH1 (rx) : ORIGIN = 0x08010000, LENGTH = 448K TCM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K - RAM (rwx) : ORIGIN = 0x20010000, LENGTH = 192K + RAM (rwx) : ORIGIN = 0x20010000, LENGTH = 176K + SRAM2 (rwx) : ORIGIN = 0x2003C000, LENGTH = 16K MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K } REGION_ALIAS("STACKRAM", TCM) REGION_ALIAS("FASTRAM", TCM) +REGION_ALIAS("DMARAM", SRAM2) __firmware_start = ORIGIN(FLASH); diff --git a/src/main/target/link/stm32_flash_f745xg.ld b/src/main/target/link/stm32_flash_f745xg.ld index ddb73a4dc50..54981a7ae1e 100644 --- a/src/main/target/link/stm32_flash_f745xg.ld +++ b/src/main/target/link/stm32_flash_f745xg.ld @@ -38,11 +38,13 @@ MEMORY FLASH1 (rx) : ORIGIN = 0x08010000, LENGTH = 960K TCM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K - RAM (rwx) : ORIGIN = 0x20010000, LENGTH = 256K + RAM (rwx) : ORIGIN = 0x20010000, LENGTH = 240K + SRAM2 (rwx) : ORIGIN = 0x2004C000, LENGTH = 16K MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K } /* note CCM could be used for stack */ REGION_ALIAS("STACKRAM", TCM) REGION_ALIAS("FASTRAM", TCM) +REGION_ALIAS("DMARAM", SRAM2) INCLUDE "stm32_flash_f7_split.ld" diff --git a/src/main/target/link/stm32_flash_f745xg_for_bl.ld b/src/main/target/link/stm32_flash_f745xg_for_bl.ld index c7667d1dc26..54a5bddcb7d 100644 --- a/src/main/target/link/stm32_flash_f745xg_for_bl.ld +++ b/src/main/target/link/stm32_flash_f745xg_for_bl.ld @@ -38,12 +38,14 @@ MEMORY FLASH1 (rx) : ORIGIN = 0x08018000, LENGTH = 928K TCM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K - RAM (rwx) : ORIGIN = 0x20010000, LENGTH = 256K + RAM (rwx) : ORIGIN = 0x20010000, LENGTH = 240K + SRAM2 (rwx) : ORIGIN = 0x2004C000, LENGTH = 16K MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K } /* note CCM could be used for stack */ REGION_ALIAS("STACKRAM", TCM) REGION_ALIAS("FASTRAM", TCM) +REGION_ALIAS("DMARAM", SRAM2) __firmware_start = ORIGIN(FLASH); diff --git a/src/main/target/link/stm32_flash_f765xg.ld b/src/main/target/link/stm32_flash_f765xg.ld index ea548ed4ff3..2dc4e906677 100644 --- a/src/main/target/link/stm32_flash_f765xg.ld +++ b/src/main/target/link/stm32_flash_f765xg.ld @@ -48,5 +48,6 @@ MEMORY REGION_ALIAS("STACKRAM", DTCM_RAM) REGION_ALIAS("FASTRAM", DTCM_RAM) REGION_ALIAS("RAM", SRAM1) +REGION_ALIAS("DMARAM", SRAM2) INCLUDE "stm32_flash_f7_split.ld" diff --git a/src/main/target/link/stm32_flash_f765xg_for_bl.ld b/src/main/target/link/stm32_flash_f765xg_for_bl.ld index b50247b015d..9405858f04d 100644 --- a/src/main/target/link/stm32_flash_f765xg_for_bl.ld +++ b/src/main/target/link/stm32_flash_f765xg_for_bl.ld @@ -48,6 +48,7 @@ MEMORY REGION_ALIAS("STACKRAM", DTCM_RAM) REGION_ALIAS("FASTRAM", DTCM_RAM) REGION_ALIAS("RAM", SRAM1) +REGION_ALIAS("DMARAM", SRAM2) __firmware_start = ORIGIN(FLASH); diff --git a/src/main/target/link/stm32_flash_f765xi.ld b/src/main/target/link/stm32_flash_f765xi.ld index 130169290ea..c1165c25dbc 100644 --- a/src/main/target/link/stm32_flash_f765xi.ld +++ b/src/main/target/link/stm32_flash_f765xi.ld @@ -51,5 +51,6 @@ REGION_ALIAS("FLASH1", AXIM_FLASH1) REGION_ALIAS("STACKRAM", DTCM_RAM) REGION_ALIAS("FASTRAM", DTCM_RAM) REGION_ALIAS("RAM", SRAM1) +REGION_ALIAS("DMARAM", SRAM2) INCLUDE "stm32_flash_f7_split.ld" diff --git a/src/main/target/link/stm32_flash_f765xi_for_bl.ld b/src/main/target/link/stm32_flash_f765xi_for_bl.ld index 14f2a4bedff..eb9c3a820cd 100644 --- a/src/main/target/link/stm32_flash_f765xi_for_bl.ld +++ b/src/main/target/link/stm32_flash_f765xi_for_bl.ld @@ -51,6 +51,7 @@ REGION_ALIAS("FLASH1", AXIM_FLASH1) REGION_ALIAS("STACKRAM", DTCM_RAM) REGION_ALIAS("FASTRAM", DTCM_RAM) REGION_ALIAS("RAM", SRAM1) +REGION_ALIAS("DMARAM", SRAM2) __firmware_start = ORIGIN(AXIM_FLASH); diff --git a/src/main/target/link/stm32_flash_f7_split.ld b/src/main/target/link/stm32_flash_f7_split.ld index 4738eb7af5e..bbd5cf5f99c 100644 --- a/src/main/target/link/stm32_flash_f7_split.ld +++ b/src/main/target/link/stm32_flash_f7_split.ld @@ -140,6 +140,17 @@ SECTIONS __bss_end__ = _ebss; } >RAM + /* DMA buffers, in a region the MPU keeps out of the D-cache (memprot_stm32f7xx.c) */ + .DMA_RAM (NOLOAD) : + { + . = ALIGN(32); + PROVIDE(dmaram_start = .); + *(.DMA_RAM) + *(.DMA_RAM*) + . = ALIGN(32); + PROVIDE(dmaram_end = .); + } >DMARAM + .fastram_bss (NOLOAD) : { __fastram_bss_start__ = .; diff --git a/src/main/target/system_stm32f7xx.c b/src/main/target/system_stm32f7xx.c index ea974199681..c1de7010047 100644 --- a/src/main/target/system_stm32f7xx.c +++ b/src/main/target/system_stm32f7xx.c @@ -66,6 +66,7 @@ #include #include "stm32f7xx.h" #include "drivers/system.h" +#include "drivers/memprot.h" #if !defined (HSE_VALUE) #define HSE_VALUE ((uint32_t)8000000) /*!< Default value of the External oscillator in Hz */ @@ -296,11 +297,18 @@ void SystemInit(void) SCB->VTOR = (uint32_t) &isr_vector_table_base; #endif +#ifndef BOOTLOADER + // DMA buffers sit in a region the MPU keeps out of the D-cache + memProtConfigure(mpuRegions, mpuRegionCount); +#endif + /* Enable I-Cache */ SCB_EnableICache(); +#ifndef BOOTLOADER /* Enable D-Cache */ - //SCB_EnableDCache(); + SCB_EnableDCache(); +#endif /* Configure the system clock to 216 MHz */ SystemClock_Config();