From 71962eb689f50059cd2e49919a386bb85fcadaf3 Mon Sep 17 00:00:00 2001 From: snkymkrct Date: Fri, 28 Mar 2025 23:15:57 +0100 Subject: [PATCH 1/5] Some peripheral support for the Daisy Seed stm32H750 board. - Added the SDRAM controller and set up heap to use the 64 MB external RAM - Added the rest of the board pin definitions from the pinout - Did peripheral pins cleanup for the stm32H750 chip - Added SDMMC peripheral and sdioio module support - Added pwmio support and started work on audiopwmio --- locale/circuitpython.pot | 5 + ports/stm/Makefile | 7 + .../daisy_seed_with_sdram/mpconfigboard.h | 37 ++ .../daisy_seed_with_sdram/mpconfigboard.mk | 4 + ports/stm/boards/daisy_seed_with_sdram/pins.c | 48 +++ ports/stm/common-hal/sdioio/SDCard.c | 49 ++- ports/stm/peripherals/periph.h | 2 +- ports/stm/peripherals/sdram.c | 371 ++++++++++++++++++ ports/stm/peripherals/sdram.h | 17 + .../peripherals/stm32h7/stm32h743xx/periph.h | 1 + .../peripherals/stm32h7/stm32h750xx/periph.c | 208 ++++++++-- .../peripherals/stm32h7/stm32h750xx/periph.h | 31 +- ports/stm/peripherals/timers.c | 98 ++++- ports/stm/peripherals/timers.h | 7 +- ports/stm/supervisor/port.c | 82 ++++ 15 files changed, 912 insertions(+), 55 deletions(-) create mode 100644 ports/stm/peripherals/sdram.c create mode 100644 ports/stm/peripherals/sdram.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 687cf5f071524..12a6fed68c9a1 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1369,6 +1369,11 @@ msgstr "" msgid "MITM security not supported" msgstr "" +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "MMC/SDIO Clock Error %x" +msgstr "" + #: shared-bindings/is31fl3741/IS31FL3741.c msgid "Mapping must be a tuple" msgstr "" diff --git a/ports/stm/Makefile b/ports/stm/Makefile index ec5ba752d4143..da4a2373d2857 100755 --- a/ports/stm/Makefile +++ b/ports/stm/Makefile @@ -169,6 +169,13 @@ ifeq ($(MCU_VARIANT),$(filter $(MCU_VARIANT),STM32F765xx STM32F767xx STM32F769xx SRC_STM32 += $(HAL_DIR)/Src/stm32$(MCU_SERIES_LOWER)xx_hal_uart_ex.c endif +ifeq ($(MCU_VARIANT),$(filter $(MCU_VARIANT),STM32H750xx)) + C_DEFS += -DHAL_SDRAM_MODULE_ENABLED + SRC_STM32 += st_driver/stm32$(MCU_SERIES_LOWER)xx_hal_driver/Src/stm32h7xx_hal_sdram.c + SRC_STM32 += st_driver/stm32$(MCU_SERIES_LOWER)xx_hal_driver/Src/stm32h7xx_ll_fmc.c + SRC_C += peripherals/sdram.c +endif + SRC_STM32 += boards/system_stm32$(MCU_SERIES_LOWER)xx.c SRC_C += \ diff --git a/ports/stm/boards/daisy_seed_with_sdram/mpconfigboard.h b/ports/stm/boards/daisy_seed_with_sdram/mpconfigboard.h index f0af0a0732b60..2cc74edd07be5 100644 --- a/ports/stm/boards/daisy_seed_with_sdram/mpconfigboard.h +++ b/ports/stm/boards/daisy_seed_with_sdram/mpconfigboard.h @@ -31,3 +31,40 @@ // for RNG not audio #define CPY_CLK_USB_USES_AUDIOPLL (1) + +// SDRAM -- on FMC controller + +#define CPY_SDRAM_REGION MPU_REGION_NUMBER10 +#define CPY_SDRAM_REGION_SIZE MPU_REGION_SIZE_64MB + +#define CIRCUITPY_HW_FMC_SDCKE0 +#define CIRCUITPY_HW_FMC_SDNE0 + +#define CIRCUITPY_HW_SDRAM_SIZE (64 * 1024 * 1024) // 64 MByte +#define CIRCUITPY_HW_SDRAM_STARTUP_TEST (1) +#define CIRCUITPY_HW_FMC_SWAP_BANKS (0) + +#define CIRCUITPY_HW_SDRAM_CLOCK_PERIOD 2 +#define CIRCUITPY_HW_SDRAM_CAS_LATENCY 3 +#define CIRCUITPY_HW_SDRAM_FREQUENCY_KHZ (100000) // 100 MHz +#define CIRCUITPY_HW_SDRAM_TIMING_TMRD (2) +#define CIRCUITPY_HW_SDRAM_TIMING_TXSR (8) +#define CIRCUITPY_HW_SDRAM_TIMING_TRAS (5) +#define CIRCUITPY_HW_SDRAM_TIMING_TRC (6) +#define CIRCUITPY_HW_SDRAM_TIMING_TWR (3) +#define CIRCUITPY_HW_SDRAM_TIMING_TRP (2) +#define CIRCUITPY_HW_SDRAM_TIMING_TRCD (2) + +#define CIRCUITPY_HW_SDRAM_ROW_BITS_NUM 13 +#define CIRCUITPY_HW_SDRAM_MEM_BUS_WIDTH 32 +#define CIRCUITPY_HW_SDRAM_REFRESH_CYCLES 8192 + +#define CIRCUITPY_HW_SDRAM_COLUMN_BITS_NUM 9 +#define CIRCUITPY_HW_SDRAM_INTERN_BANKS_NUM 4 +#define CIRCUITPY_HW_SDRAM_RPIPE_DELAY 0 +#define CIRCUITPY_HW_SDRAM_RBURST (1) +#define CIRCUITPY_HW_SDRAM_WRITE_PROTECTION (0) + +#define CIRCUITPY_HW_SDRAM_AUTOREFRESH_NUM (8) +#define CIRCUITPY_HW_SDRAM_BURST_LENGTH 4 +#define CIRCUITPY_HW_SDRAM_REFRESH_RATE (64) // ms diff --git a/ports/stm/boards/daisy_seed_with_sdram/mpconfigboard.mk b/ports/stm/boards/daisy_seed_with_sdram/mpconfigboard.mk index 7b7d4ed4448f7..a43c4ed177b6a 100644 --- a/ports/stm/boards/daisy_seed_with_sdram/mpconfigboard.mk +++ b/ports/stm/boards/daisy_seed_with_sdram/mpconfigboard.mk @@ -12,3 +12,7 @@ MCU_PACKAGE = UFBGA176 LD_COMMON = boards/common_tcm.ld LD_FILE = boards/STM32H750.ld + +CIRCUITPY_SDIOIO = 1 +CIRCUITPY_PWMIO = 1 +CIRCUITPY_AUDIOPWMIO = 1 diff --git a/ports/stm/boards/daisy_seed_with_sdram/pins.c b/ports/stm/boards/daisy_seed_with_sdram/pins.c index f5bef6d2b3906..b8f8f05b901c7 100644 --- a/ports/stm/boards/daisy_seed_with_sdram/pins.c +++ b/ports/stm/boards/daisy_seed_with_sdram/pins.c @@ -6,8 +6,56 @@ #include "shared-bindings/board/__init__.h" +// See pinout on Daisy Seed product page +// https://electro-smith.com/products/daisy-seed?variant=45234245108004 static const mp_rom_map_elem_t board_module_globals_table[] = { {MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_PC07)}, {MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_PTR(&pin_PG03)}, + {MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PB12)}, + {MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PC11)}, + {MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PC10)}, + {MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PC09)}, + {MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PC08)}, + {MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PD02)}, + {MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PC12)}, + {MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PG10)}, + {MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PG11)}, + {MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PB04)}, + {MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PB05)}, + {MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PB08)}, + {MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_PB09)}, + {MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PB06)}, + {MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_PB07)}, + + {MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_PC00)}, + {MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PC00)}, + {MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_PA03)}, + {MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PA03)}, + {MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_PB01)}, + {MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB01)}, + {MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_PA07)}, + {MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PA07)}, + {MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_PA06)}, + {MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PA06)}, + {MP_ROM_QSTR(MP_QSTR_D20), MP_ROM_PTR(&pin_PC01)}, + {MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PC01)}, + {MP_ROM_QSTR(MP_QSTR_D21), MP_ROM_PTR(&pin_PC04)}, + {MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_PC04)}, + {MP_ROM_QSTR(MP_QSTR_D22), MP_ROM_PTR(&pin_PA05)}, + {MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_PA05)}, + {MP_ROM_QSTR(MP_QSTR_D23), MP_ROM_PTR(&pin_PA04)}, + {MP_ROM_QSTR(MP_QSTR_A8), MP_ROM_PTR(&pin_PA04)}, + {MP_ROM_QSTR(MP_QSTR_D24), MP_ROM_PTR(&pin_PA01)}, + {MP_ROM_QSTR(MP_QSTR_A9), MP_ROM_PTR(&pin_PA01)}, + {MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_PA00)}, + {MP_ROM_QSTR(MP_QSTR_A10), MP_ROM_PTR(&pin_PA00)}, + {MP_ROM_QSTR(MP_QSTR_D26), MP_ROM_PTR(&pin_PD11)}, + {MP_ROM_QSTR(MP_QSTR_D27), MP_ROM_PTR(&pin_PG09)}, + {MP_ROM_QSTR(MP_QSTR_D28), MP_ROM_PTR(&pin_PA02)}, + {MP_ROM_QSTR(MP_QSTR_A11), MP_ROM_PTR(&pin_PA02)}, + {MP_ROM_QSTR(MP_QSTR_D29), MP_ROM_PTR(&pin_PB14)}, + {MP_ROM_QSTR(MP_QSTR_D30), MP_ROM_PTR(&pin_PB15)}, + }; + MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/stm/common-hal/sdioio/SDCard.c b/ports/stm/common-hal/sdioio/SDCard.c index 92c16aef84769..a5c8b0404a0fb 100644 --- a/ports/stm/common-hal/sdioio/SDCard.c +++ b/ports/stm/common-hal/sdioio/SDCard.c @@ -104,7 +104,11 @@ void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, uint8_t num_data, const mcu_pin_obj_t **data, uint32_t frequency) { int periph_index = check_pins(self, clock, command, num_data, data); + #ifdef STM32H750xx + SDMMC_TypeDef *SDMMCx = mcu_sdio_banks[periph_index - 1]; + #else SDIO_TypeDef *SDIOx = mcu_sdio_banks[periph_index - 1]; + #endif GPIO_InitTypeDef GPIO_InitStruct = {0}; @@ -128,6 +132,25 @@ void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, GPIO_InitStruct.Pin = pin_mask(clock->number); HAL_GPIO_Init(pin_port(clock->port), &GPIO_InitStruct); + #ifdef STM32H750xx + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SDMMC; + PeriphClkInitStruct.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("MMC/SDIO Clock Error %x")); + } + __HAL_RCC_SDMMC1_CLK_ENABLE(); + + self->handle.Init.ClockDiv = SDMMC_NSPEED_CLK_DIV; + self->handle.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + self->handle.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; + self->handle.Init.BusWide = SDMMC_BUS_WIDE_1B; + // For the SDMMC controller Hardware Flow Control needs to be enabled + // at the default speed of 25MHz, in order to avoid FIFO underrun (TX mode) + // and overrun (RX mode) errors. + self->handle.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_ENABLE; + self->handle.Instance = SDMMCx; + #else __HAL_RCC_SDIO_CLK_ENABLE(); self->handle.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV; @@ -137,6 +160,7 @@ void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, self->handle.Init.BusWide = SDIO_BUS_WIDE_1B; self->handle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; self->handle.Instance = SDIOx; + #endif HAL_StatusTypeDef r = HAL_SD_Init(&self->handle); if (r != HAL_OK) { @@ -150,9 +174,14 @@ void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, } self->num_data = 1; + #ifdef STM32H750xx + uint32_t bus_wide_opt = SDMMC_BUS_WIDE_4B; + #else + uint32_t bus_wide_opt = SDIO_BUS_WIDE_4B; + #endif if (num_data == 4) { - if ((r = HAL_SD_ConfigWideBusOperation(&self->handle, SDIO_BUS_WIDE_4B)) == HAL_SD_ERROR_NONE) { - self->handle.Init.BusWide = SDIO_BUS_WIDE_4B; + if ((r = HAL_SD_ConfigWideBusOperation(&self->handle, bus_wide_opt)) == HAL_SD_ERROR_NONE) { + self->handle.Init.BusWide = bus_wide_opt; self->num_data = 4; } else { } @@ -216,7 +245,13 @@ int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t sta wait_write_complete(self); self->state_programming = true; common_hal_mcu_disable_interrupts(); - HAL_StatusTypeDef r = HAL_SD_WriteBlocks(&self->handle, bufinfo->buf, start_block, bufinfo->len / 512, 1000); + #ifdef STM32H750xx + // longer timeouts needed because code executing from QSPI is slower + uint32_t time_out = SDMMC_DATATIMEOUT; + #else + uint32_t time_out = 1000; + #endif + HAL_StatusTypeDef r = HAL_SD_WriteBlocks(&self->handle, bufinfo->buf, start_block, bufinfo->len / 512, time_out); common_hal_mcu_enable_interrupts(); if (r != HAL_OK) { return -EIO; @@ -229,7 +264,13 @@ int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t star check_whole_block(bufinfo); wait_write_complete(self); common_hal_mcu_disable_interrupts(); - HAL_StatusTypeDef r = HAL_SD_ReadBlocks(&self->handle, bufinfo->buf, start_block, bufinfo->len / 512, 1000); + #ifdef STM32H750xx + // longer timeouts needed because code executing from QSPI is slower + uint32_t time_out = SDMMC_DATATIMEOUT; + #else + uint32_t time_out = 1000; + #endif + HAL_StatusTypeDef r = HAL_SD_ReadBlocks(&self->handle, bufinfo->buf, start_block, bufinfo->len / 512, time_out); common_hal_mcu_enable_interrupts(); if (r != HAL_OK) { return -EIO; diff --git a/ports/stm/peripherals/periph.h b/ports/stm/peripherals/periph.h index e1a922cebc9d7..1c6f5f214fee9 100644 --- a/ports/stm/peripherals/periph.h +++ b/ports/stm/peripherals/periph.h @@ -30,7 +30,7 @@ typedef struct { // Timer Peripheral typedef struct { - uint8_t tim_index : 4; + uint8_t tim_index : 5; uint8_t altfn_index : 4; uint8_t channel_index : 4; const mcu_pin_obj_t *pin; diff --git a/ports/stm/peripherals/sdram.c b/ports/stm/peripherals/sdram.c new file mode 100644 index 0000000000000..159d14c410295 --- /dev/null +++ b/ports/stm/peripherals/sdram.c @@ -0,0 +1,371 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 snkYmkrct +// +// based on implementation from https://github.com/micropython/micropython/blob/master/ports/stm32/sdram.c +// +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include STM32_HAL_H +#include "common-hal/microcontroller/Pin.h" +#include "peripherals/periph.h" +#if defined(STM32H7) +#include "stm32h7xx_ll_fmc.h" +#include "stm32h7xx_hal_sdram.h" +#include "stm32h7xx_hal_gpio.h" +#include "stm32h7xx_hal_cortex.h" +#endif +#ifdef STM32H750xx +#include "stm32h7/stm32h750xx/periph.h" +#endif + + +#include "sdram.h" + + +#if MICROPY_DEBUG_VERBOSE // print debugging info +#define DEBUG_PRINT (1) +#define DEBUG_printf DEBUG_printf +#define DEBUG_OP_printf(...) DEBUG_printf(__VA_ARGS__) +#else // don't print debugging info +#define DEBUG_printf(...) (void)0 +#define DEBUG_OP_printf(...) (void)0 +#endif + +#define SDRAM_TIMEOUT ((uint32_t)0xFFFF) +#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001) +#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002) +#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004) +#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008) +#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020) +#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030) +#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) + +#if defined(CIRCUITPY_HW_FMC_SDCKE0) && defined(CIRCUITPY_HW_FMC_SDNE0) +#define FMC_SDRAM_BANK FMC_SDRAM_BANK1 +#define FMC_SDRAM_CMD_TARGET_BANK FMC_SDRAM_CMD_TARGET_BANK1 +#if CIRCUITPY_HW_FMC_SWAP_BANKS +#define SDRAM_START_ADDRESS 0x60000000 +#else +#define SDRAM_START_ADDRESS 0xC0000000 +#endif +#elif defined(CIRCUITPY_HW_FMC_SDCKE1) && defined(CIRCUITPY_HW_FMC_SDNE1) +#define FMC_SDRAM_BANK FMC_SDRAM_BANK2 +#define FMC_SDRAM_CMD_TARGET_BANK FMC_SDRAM_CMD_TARGET_BANK2 +#if CIRCUITPY_HW_FMC_SWAP_BANKS +#define SDRAM_START_ADDRESS 0x70000000 +#else +#define SDRAM_START_ADDRESS 0xD0000000 +#endif +#endif + +#ifdef FMC_SDRAM_BANK + +static uint8_t FMC_Initialized = 0; +static SDRAM_HandleTypeDef hsdram = {0}; + + +static void sdram_init_seq(void); + +bool sdram_init(void) { + FMC_SDRAM_TimingTypeDef SDRAM_Timing = {0}; + + if (!FMC_Initialized) { + + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + + /** Initializes the peripherals clock + */ + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_FMC; + PeriphClkInitStruct.FmcClockSelection = RCC_FMCCLKSOURCE_D1HCLK; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { + DEBUG_printf("sdram: %s", "periph init clock error"); + } + /* Peripheral clock enable */ + __HAL_RCC_FMC_CLK_ENABLE(); + FMC_Initialized = 1; + } + + #if CIRCUITPY_HW_FMC_SWAP_BANKS + HAL_SetFMCMemorySwappingConfig(FMC_SWAPBMAP_SDRAM_SRAM); + #endif + + for (uint i = 0; i < MP_ARRAY_SIZE(sdram_pin_list); i++) { + GPIO_InitTypeDef GPIO_InitStruct = {0}; + GPIO_InitStruct.Pin = pin_mask(sdram_pin_list[i].pin->number); + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF12_FMC; + HAL_GPIO_Init(pin_port(sdram_pin_list[i].pin->port), &GPIO_InitStruct); + never_reset_pin_number(sdram_pin_list[i].pin->port, sdram_pin_list[i].pin->number); + } + /* SDRAM device configuration */ + hsdram.Instance = FMC_SDRAM_DEVICE; + /* Timing configuration for 90 Mhz of SD clock frequency (180Mhz/2) */ + /* TMRD: 2 Clock cycles */ + SDRAM_Timing.LoadToActiveDelay = CIRCUITPY_HW_SDRAM_TIMING_TMRD; + /* TXSR: min=70ns (6x11.90ns) */ + SDRAM_Timing.ExitSelfRefreshDelay = CIRCUITPY_HW_SDRAM_TIMING_TXSR; + /* TRAS */ + SDRAM_Timing.SelfRefreshTime = CIRCUITPY_HW_SDRAM_TIMING_TRAS; + /* TRC */ + SDRAM_Timing.RowCycleDelay = CIRCUITPY_HW_SDRAM_TIMING_TRC; + /* TWR */ + SDRAM_Timing.WriteRecoveryTime = CIRCUITPY_HW_SDRAM_TIMING_TWR; + /* TRP */ + SDRAM_Timing.RPDelay = CIRCUITPY_HW_SDRAM_TIMING_TRP; + /* TRCD */ + SDRAM_Timing.RCDDelay = CIRCUITPY_HW_SDRAM_TIMING_TRCD; + + #define _FMC_INIT(x, n) x##_##n + #define FMC_INIT(x, n) _FMC_INIT(x, n) + + hsdram.Init.SDBank = FMC_SDRAM_BANK; + hsdram.Init.ColumnBitsNumber = FMC_INIT(FMC_SDRAM_COLUMN_BITS_NUM, CIRCUITPY_HW_SDRAM_COLUMN_BITS_NUM); + hsdram.Init.RowBitsNumber = FMC_INIT(FMC_SDRAM_ROW_BITS_NUM, CIRCUITPY_HW_SDRAM_ROW_BITS_NUM); + hsdram.Init.MemoryDataWidth = FMC_INIT(FMC_SDRAM_MEM_BUS_WIDTH, CIRCUITPY_HW_SDRAM_MEM_BUS_WIDTH); + hsdram.Init.InternalBankNumber = FMC_INIT(FMC_SDRAM_INTERN_BANKS_NUM, CIRCUITPY_HW_SDRAM_INTERN_BANKS_NUM); + hsdram.Init.CASLatency = FMC_INIT(FMC_SDRAM_CAS_LATENCY, CIRCUITPY_HW_SDRAM_CAS_LATENCY); + hsdram.Init.SDClockPeriod = FMC_INIT(FMC_SDRAM_CLOCK_PERIOD, CIRCUITPY_HW_SDRAM_CLOCK_PERIOD); + hsdram.Init.ReadPipeDelay = FMC_INIT(FMC_SDRAM_RPIPE_DELAY, CIRCUITPY_HW_SDRAM_RPIPE_DELAY); + hsdram.Init.ReadBurst = (CIRCUITPY_HW_SDRAM_RBURST) ? FMC_SDRAM_RBURST_ENABLE : FMC_SDRAM_RBURST_DISABLE; + hsdram.Init.WriteProtection = (CIRCUITPY_HW_SDRAM_WRITE_PROTECTION) ? FMC_SDRAM_WRITE_PROTECTION_ENABLE : FMC_SDRAM_WRITE_PROTECTION_DISABLE; + + /* Initialize the SDRAM controller */ + if (HAL_SDRAM_Init(&hsdram, &SDRAM_Timing) != HAL_OK) { + DEBUG_printf("sdram: %s", "init error"); + return false; + } + + sdram_init_seq(); + + return true; +} + +void sdram_deinit(void) { + FMC_SDRAM_CommandTypeDef command = {0}; + if (FMC_Initialized) { + /* Send the module into powerdown mode */ + command.CommandMode = FMC_SDRAM_CMD_POWERDOWN_MODE; + command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + command.AutoRefreshNumber = 1; + command.ModeRegisterDefinition = 0; + + /* Send the command */ + if (HAL_SDRAM_SendCommand(&hsdram, &command, HAL_MAX_DELAY) != HAL_OK) { + DEBUG_printf("sdram power off error:%s:%d", __func__, __LINE__); + } + } +} + +void *sdram_start(void) { + return (void *)SDRAM_START_ADDRESS; +} + +void *sdram_end(void) { + return (void *)(SDRAM_START_ADDRESS + CIRCUITPY_HW_SDRAM_SIZE); +} + +uint32_t sdram_size(void) { + return CIRCUITPY_HW_SDRAM_SIZE; +} + +static void sdram_init_seq(void) { + FMC_SDRAM_CommandTypeDef command = {0}; + /* Program the SDRAM external device */ + __IO uint32_t tmpmrd = 0; + + /* Configure a clock configuration enable command */ + command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; + command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK; + command.AutoRefreshNumber = 1; + command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&hsdram, &command, HAL_MAX_DELAY); + + /* Insert 100 ms delay */ + HAL_Delay(100); + + /* Configure a PALL (precharge all) command */ + command.CommandMode = FMC_SDRAM_CMD_PALL; + command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK; + command.AutoRefreshNumber = 1; + command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&hsdram, &command, HAL_MAX_DELAY); + + /* Configure a Auto-Refresh command */ + command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; + command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK; + command.AutoRefreshNumber = CIRCUITPY_HW_SDRAM_AUTOREFRESH_NUM; + command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&hsdram, &command, HAL_MAX_DELAY); + + /* Program the external memory mode register */ + tmpmrd = (uint32_t)0x0 | FMC_INIT(SDRAM_MODEREG_BURST_LENGTH, CIRCUITPY_HW_SDRAM_BURST_LENGTH) | + SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | + FMC_INIT(SDRAM_MODEREG_CAS_LATENCY, CIRCUITPY_HW_SDRAM_CAS_LATENCY) | + SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; + + command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; + command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK; + command.AutoRefreshNumber = 1; + command.ModeRegisterDefinition = tmpmrd; + + /* Send the command */ + HAL_SDRAM_SendCommand(&hsdram, &command, HAL_MAX_DELAY); + + /* Set the refresh rate counter. + Assuming 100MHz frequency, 8192 refresh cycles and 64ms refresh rate: + RefreshRate = 64 ms / 8192 cyc = 7.8125 us/cyc + RefreshCycles = 7.8125 us * 100 MHz = 782 + According to the formula on p.1665 of the reference manual, + we also need to subtract 20 from the value, so the target + refresh rate is 782 - 20 = 762 + */ + + #define REFRESH_COUNT (CIRCUITPY_HW_SDRAM_REFRESH_RATE * CIRCUITPY_HW_SDRAM_FREQUENCY_KHZ / CIRCUITPY_HW_SDRAM_REFRESH_CYCLES - 20) + + HAL_SDRAM_ProgramRefreshRate(&hsdram, REFRESH_COUNT); + + #if defined(STM32F7) || defined(STM32H7) + __disable_irq(); + MPU_Region_InitTypeDef MPU_InitStruct = {0}; + /** Enable caching for SDRAM to support non-alligned access. + */ + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = CPY_SDRAM_REGION; + MPU_InitStruct.BaseAddress = SDRAM_START_ADDRESS; + MPU_InitStruct.Size = CPY_SDRAM_REGION_SIZE; + MPU_InitStruct.SubRegionDisable = 0x0; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; + MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; + MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; + + HAL_MPU_ConfigRegion(&MPU_InitStruct); + __ISB(); + __DSB(); + __DMB(); + __enable_irq(); + + #endif + +} + +bool __attribute__((optimize("Os"))) sdram_test(bool exhaustive) { + uint8_t const pattern = 0xaa; + uint8_t const antipattern = 0x55; + volatile uint8_t *const mem_base = (uint8_t *)sdram_start(); + + char error_buffer[1024]; + + DEBUG_printf("sdram: %s\n", "sdram test started"); + + #if (__DCACHE_PRESENT == 1) + bool i_cache_disabled = false; + bool d_cache_disabled = false; + + // Disable caches for testing. + if (SCB->CCR & (uint32_t)SCB_CCR_IC_Msk) { + SCB_DisableICache(); + i_cache_disabled = true; + } + + if (SCB->CCR & (uint32_t)SCB_CCR_DC_Msk) { + SCB_DisableDCache(); + d_cache_disabled = true; + } + #endif + + // Test data bus + for (uint32_t i = 0; i < CIRCUITPY_HW_SDRAM_MEM_BUS_WIDTH; i++) { + *((volatile uint32_t *)mem_base) = (1u << i); + __DSB(); + if (*((volatile uint32_t *)mem_base) != (1u << i)) { + snprintf(error_buffer, sizeof(error_buffer), + "Data bus test failed at 0x%p expected 0x%x found 0x%lx", + &mem_base[0], (1 << i), ((volatile uint32_t *)mem_base)[0]); + DEBUG_printf("error: %s\n", error_buffer); + return false; + } + } + + // Test address bus + for (uint32_t i = 1; i < CIRCUITPY_HW_SDRAM_SIZE; i <<= 1) { + mem_base[i] = pattern; + __DSB(); + if (mem_base[i] != pattern) { + snprintf(error_buffer, sizeof(error_buffer), + "Address bus test failed at 0x%p expected 0x%x found 0x%x", + &mem_base[i], pattern, mem_base[i]); + DEBUG_printf("error: %s\n", error_buffer); + return false; + } + } + + // Check for aliasing (overlapping addresses) + mem_base[0] = antipattern; + __DSB(); + for (uint32_t i = 1; i < CIRCUITPY_HW_SDRAM_SIZE; i <<= 1) { + if (mem_base[i] != pattern) { + snprintf(error_buffer, sizeof(error_buffer), + "Address bus overlap at 0x%p expected 0x%x found 0x%x", + &mem_base[i], pattern, mem_base[i]); + DEBUG_printf("error: %s\n", error_buffer); + return false; + } + } + + // Test all RAM cells + if (exhaustive) { + // Write all memory first then compare, so even if the cache + // is enabled, it's not just writing and reading from cache. + // Note: This test should also detect refresh rate issues. + for (uint32_t i = 0; i < CIRCUITPY_HW_SDRAM_SIZE; i++) { + mem_base[i] = ((i % 2) ? pattern : antipattern); + } + + for (uint32_t i = 0; i < CIRCUITPY_HW_SDRAM_SIZE; i++) { + if (mem_base[i] != ((i % 2) ? pattern : antipattern)) { + snprintf(error_buffer, sizeof(error_buffer), + "Address bus slow test failed at 0x%p expected 0x%x found 0x%x", + &mem_base[i], ((i % 2) ? pattern : antipattern), mem_base[i]); + DEBUG_printf("error: %s\n", error_buffer); + return false; + } + } + } + + #if (__DCACHE_PRESENT == 1) + // Re-enable caches if they were enabled before the test started. + if (i_cache_disabled) { + SCB_EnableICache(); + } + + if (d_cache_disabled) { + SCB_EnableDCache(); + } + #endif + + DEBUG_printf("sdram: %s\n", "sdram test successfully!"); + + return true; +} + + +#endif // FMC_SDRAM_BANK diff --git a/ports/stm/peripherals/sdram.h b/ports/stm/peripherals/sdram.h new file mode 100644 index 0000000000000..1f5b1a4520d4e --- /dev/null +++ b/ports/stm/peripherals/sdram.h @@ -0,0 +1,17 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 snkYmkrct +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +bool sdram_init(void); +void sdram_deinit(void); +void *sdram_start(void); +void *sdram_end(void); +uint32_t sdram_size(void); +bool sdram_test(bool exhaustive); diff --git a/ports/stm/peripherals/stm32h7/stm32h743xx/periph.h b/ports/stm/peripherals/stm32h7/stm32h743xx/periph.h index fa4ec7f6e5621..2ff49c8503ce5 100644 --- a/ports/stm/peripherals/stm32h7/stm32h743xx/periph.h +++ b/ports/stm/peripherals/stm32h7/stm32h743xx/periph.h @@ -30,3 +30,4 @@ extern const mcu_periph_obj_t mcu_uart_rx_list[26]; #define TIM_BANK_ARRAY_LEN 14 #define TIM_PIN_ARRAY_LEN 58 extern TIM_TypeDef *mcu_tim_banks[TIM_BANK_ARRAY_LEN]; +extern const mcu_tim_pin_obj_t mcu_tim_pin_list[TIM_PIN_ARRAY_LEN]; diff --git a/ports/stm/peripherals/stm32h7/stm32h750xx/periph.c b/ports/stm/peripherals/stm32h7/stm32h750xx/periph.c index 55acede594191..023e06ee32245 100644 --- a/ports/stm/peripherals/stm32h7/stm32h750xx/periph.c +++ b/ports/stm/peripherals/stm32h7/stm32h750xx/periph.c @@ -9,8 +9,10 @@ #include "peripherals/pins.h" #include "peripherals/periph.h" +// See alternate functions tables in the STM32H750xx datasheet + // I2C -I2C_TypeDef *mcu_i2c_banks[4] = {I2C1, I2C2, I2C3, I2C4}; +I2C_TypeDef *mcu_i2c_banks[MAX_I2C] = {I2C1, I2C2, I2C3, I2C4}; const mcu_periph_obj_t mcu_i2c_sda_list[12] = { PERIPH(1, 4, &pin_PB07), @@ -44,9 +46,9 @@ const mcu_periph_obj_t mcu_i2c_scl_list[12] = { // SPI -SPI_TypeDef *mcu_spi_banks[6] = {SPI1, SPI2, SPI3, SPI4, SPI5, SPI6}; +SPI_TypeDef *mcu_spi_banks[MAX_SPI] = {SPI1, SPI2, SPI3, SPI4, SPI5, SPI6}; -const mcu_periph_obj_t mcu_spi_sck_list[19] = { +const mcu_periph_obj_t mcu_spi_sck_list[18] = { PERIPH(1, 5, &pin_PA05), PERIPH(6, 8, &pin_PA05), PERIPH(2, 5, &pin_PA09), @@ -65,10 +67,9 @@ const mcu_periph_obj_t mcu_spi_sck_list[19] = { PERIPH(6, 5, &pin_PG13), PERIPH(5, 5, &pin_PH06), PERIPH(2, 5, &pin_PI01), - PERIPH(5, 5, &pin_PI00), }; -const mcu_periph_obj_t mcu_spi_mosi_list[19] = { +const mcu_periph_obj_t mcu_spi_mosi_list[18] = { PERIPH(1, 5, &pin_PA07), PERIPH(6, 8, &pin_PA07), PERIPH(3, 7, &pin_PB02), @@ -87,10 +88,9 @@ const mcu_periph_obj_t mcu_spi_mosi_list[19] = { PERIPH(5, 5, &pin_PF11), PERIPH(6, 5, &pin_PG14), PERIPH(2, 5, &pin_PI03), - PERIPH(5, 5, &pin_PI10), }; -const mcu_periph_obj_t mcu_spi_miso_list[16] = { +const mcu_periph_obj_t mcu_spi_miso_list[15] = { PERIPH(1, 5, &pin_PA06), PERIPH(6, 8, &pin_PA06), PERIPH(1, 5, &pin_PB04), @@ -106,15 +106,15 @@ const mcu_periph_obj_t mcu_spi_miso_list[16] = { PERIPH(6, 5, &pin_PG12), PERIPH(5, 5, &pin_PH07), PERIPH(2, 5, &pin_PI02), - PERIPH(5, 5, &pin_PI11), }; // UART -USART_TypeDef *mcu_uart_banks[MAX_UART] = {USART1, USART2, USART3, UART4, UART5, USART6, UART7, UART8, LPUART1}; -bool mcu_uart_has_usart[MAX_UART] = {true, true, true, false, false, true, false, false, false}; +USART_TypeDef *mcu_uart_banks[MAX_UART] = {USART1, USART2, USART3, UART4, UART5, USART6, UART7, UART8}; +// circuitpython doesn't implement USART +// bool mcu_uart_has_usart[MAX_UART] = {true, true, true, false, false, true, false, false, false}; -const mcu_periph_obj_t mcu_uart_tx_list[25] = { +const mcu_periph_obj_t mcu_uart_tx_list[24] = { PERIPH(4, 8, &pin_PA00), PERIPH(2, 7, &pin_PA02), PERIPH(1, 7, &pin_PA09), @@ -138,11 +138,10 @@ const mcu_periph_obj_t mcu_uart_tx_list[25] = { PERIPH(7, 7, &pin_PE08), PERIPH(7, 7, &pin_PF07), PERIPH(6, 7, &pin_PG14), - PERIPH(4, 8, &pin_PI13), - PERIPH(8, 8, &pin_PI08), + PERIPH(4, 8, &pin_PH13), }; -const mcu_periph_obj_t mcu_uart_rx_list[26] = { +const mcu_periph_obj_t mcu_uart_rx_list[25] = { PERIPH(4, 8, &pin_PA01), PERIPH(2, 7, &pin_PA03), PERIPH(7, 11, &pin_PA08), @@ -166,29 +165,30 @@ const mcu_periph_obj_t mcu_uart_rx_list[26] = { PERIPH(7, 7, &pin_PE07), PERIPH(7, 7, &pin_PF06), PERIPH(6, 7, &pin_PG09), - PERIPH(4, 8, &pin_PI14), + PERIPH(4, 8, &pin_PH14), PERIPH(4, 8, &pin_PI09), - PERIPH(8, 8, &pin_PI09), }; // Timers // TIM6 and TIM7 are basic timers that are only used by DAC, and don't have pins -// TODO: H7 has more timers than this, but are they tied to pins? -TIM_TypeDef *mcu_tim_banks[14] = {TIM1, TIM2, TIM3, TIM4, TIM5, NULL, NULL, TIM8, NULL, NULL, - NULL, TIM12, TIM13, TIM14}; - -const mcu_tim_pin_obj_t mcu_tim_pin_list[58] = { +TIM_TypeDef *mcu_tim_banks[TIM_BANK_ARRAY_LEN] = {TIM1, TIM2, TIM3, TIM4, TIM5, NULL, NULL, TIM8, + NULL, NULL, NULL, TIM12, TIM13, TIM14, TIM15, TIM16, TIM17}; +const mcu_tim_pin_obj_t mcu_tim_pin_list[TIM_PIN_ARRAY_LEN] = { TIM(2, 1, 1, &pin_PA00), TIM(5, 2, 1, &pin_PA00), TIM(2, 1, 2, &pin_PA01), TIM(5, 2, 2, &pin_PA01), TIM(2, 1, 3, &pin_PA02), TIM(5, 2, 3, &pin_PA02), + TIM(15, 4, 1, &pin_PA02), TIM(2, 1, 4, &pin_PA03), TIM(5, 2, 4, &pin_PA03), + TIM(15, 4, 2, &pin_PA03), TIM(2, 1, 1, &pin_PA05), TIM(3, 2, 1, &pin_PA06), + TIM(13, 9, 1, &pin_PA06), TIM(3, 2, 2, &pin_PA07), + TIM(14, 9, 1, &pin_PA07), TIM(1, 1, 1, &pin_PA08), TIM(1, 1, 2, &pin_PA09), TIM(1, 1, 3, &pin_PA10), @@ -205,6 +205,8 @@ const mcu_tim_pin_obj_t mcu_tim_pin_list[58] = { TIM(4, 2, 4, &pin_PB09), TIM(2, 1, 3, &pin_PB10), TIM(2, 1, 4, &pin_PB11), + TIM(12, 2, 1, &pin_PB14), + TIM(12, 2, 2, &pin_PB15), TIM(3, 2, 1, &pin_PC06), TIM(8, 3, 1, &pin_PC06), TIM(3, 2, 2, &pin_PC07), @@ -217,23 +219,167 @@ const mcu_tim_pin_obj_t mcu_tim_pin_list[58] = { TIM(4, 2, 2, &pin_PD13), TIM(4, 2, 3, &pin_PD14), TIM(4, 2, 4, &pin_PD15), + TIM(15, 4, 1, &pin_PE05), + TIM(15, 4, 2, &pin_PE06), TIM(1, 1, 1, &pin_PE09), TIM(1, 1, 2, &pin_PE11), TIM(1, 1, 3, &pin_PE13), TIM(1, 1, 4, &pin_PE14), - TIM(5, 2, 1, &pin_PI10), - TIM(5, 2, 2, &pin_PI11), - TIM(5, 2, 3, &pin_PI12), + TIM(16, 1, 1, &pin_PF06), + TIM(17, 1, 1, &pin_PF07), + TIM(13, 9, 1, &pin_PF08), + TIM(14, 9, 1, &pin_PF09), + TIM(12, 2, 1, &pin_PH06), + TIM(12, 2, 2, &pin_PH09), + TIM(5, 2, 1, &pin_PH10), + TIM(5, 2, 2, &pin_PH11), + TIM(5, 2, 3, &pin_PH12), TIM(5, 2, 4, &pin_PI00), TIM(8, 3, 4, &pin_PI02), TIM(8, 3, 1, &pin_PI05), TIM(8, 3, 2, &pin_PI06), TIM(8, 3, 3, &pin_PI07), - TIM(8, 3, 2, &pin_PI06), - TIM(8, 3, 1, &pin_PI08), - TIM(1, 1, 3, &pin_PI09), - TIM(8, 3, 2, &pin_PI10), - TIM(1, 1, 2, &pin_PI11), - TIM(8, 3, 3, &pin_PI00), - TIM(1, 1, 1, &pin_PI01), +}; + +// SDIO - H750 has a MMC interface that includes SDIO +SDMMC_TypeDef *mcu_sdio_banks[1] = {SDMMC1}; + +const mcu_periph_obj_t mcu_sdio_clock_list[1] = { + PERIPH(1, 12, &pin_PC12), +}; +const mcu_periph_obj_t mcu_sdio_command_list[1] = { + PERIPH(1, 12, &pin_PD02), +}; +const mcu_periph_obj_t mcu_sdio_data0_list[1] = { + PERIPH(1, 12, &pin_PC08), +}; +const mcu_periph_obj_t mcu_sdio_data1_list[1] = { + PERIPH(1, 12, &pin_PC09), +}; +const mcu_periph_obj_t mcu_sdio_data2_list[1] = { + PERIPH(1, 12, &pin_PC10), +}; +const mcu_periph_obj_t mcu_sdio_data3_list[1] = { + PERIPH(1, 12, &pin_PC11), +}; + + +/** FMC GPIO Configuration + PE1 ------> FMC_NBL1 + PE0 ------> FMC_NBL0 + PG15 ------> FMC_SDNCAS + PD0 ------> FMC_D2 + PI7 ------> FMC_D29 + PI6 ------> FMC_D28 + PI5 ------> FMC_NBL3 + PD1 ------> FMC_D3 + PI3 ------> FMC_D27 + PI2 ------> FMC_D26 + PI9 ------> FMC_D30 + PI4 ------> FMC_NBL2 + PH15 ------> FMC_D23 + PI1 ------> FMC_D25 + PF0 ------> FMC_A0 + PI10 ------> FMC_D31 + PH13 ------> FMC_D21 + PH14 ------> FMC_D22 + PI0 ------> FMC_D24 + PH2 ------> FMC_SDCKE0 + PH3 ------> FMC_SDNE0 + PF2 ------> FMC_A2 + PF1 ------> FMC_A1 + PG8 ------> FMC_SDCLK + PF3 ------> FMC_A3 + PF4 ------> FMC_A4 + PH5 ------> FMC_SDNWE + PF5 ------> FMC_A5 + PH12 ------> FMC_D20 + PG5 ------> FMC_BA1 + PG4 ------> FMC_BA0 + PH11 ------> FMC_D19 + PH10 ------> FMC_D18 + PD15 ------> FMC_D1 + PG2 ------> FMC_A12 + PG1 ------> FMC_A11 + PH8 ------> FMC_D16 + PH9 ------> FMC_D17 + PD14 ------> FMC_D0 + PF13 ------> FMC_A7 + PG0 ------> FMC_A10 + PE13 ------> FMC_D10 + PD10 ------> FMC_D15 + PF12 ------> FMC_A6 + PF15 ------> FMC_A9 + PE8 ------> FMC_D5 + PE9 ------> FMC_D6 + PE11 ------> FMC_D8 + PE14 ------> FMC_D11 + PD9 ------> FMC_D14 + PD8 ------> FMC_D13 + PF11 ------> FMC_SDNRAS + PF14 ------> FMC_A8 + PE7 ------> FMC_D4 + PE10 ------> FMC_D7 + PE12 ------> FMC_D9 + PE15 ------> FMC_D12 + */ + +const mcu_periph_obj_t sdram_pin_list[57] = { + PERIPH(4, 12, &pin_PE01), + PERIPH(4, 12, &pin_PE00), + PERIPH(6, 12, &pin_PG15), + PERIPH(3, 12, &pin_PD00), + PERIPH(8, 12, &pin_PI07), + PERIPH(8, 12, &pin_PI06), + PERIPH(8, 12, &pin_PI05), + PERIPH(3, 12, &pin_PD01), + PERIPH(8, 12, &pin_PI03), + PERIPH(8, 12, &pin_PI02), + PERIPH(8, 12, &pin_PI09), + PERIPH(8, 12, &pin_PI04), + PERIPH(7, 12, &pin_PH15), + PERIPH(8, 12, &pin_PI01), + PERIPH(5, 12, &pin_PF00), + PERIPH(8, 12, &pin_PI10), + PERIPH(7, 12, &pin_PH13), + PERIPH(7, 12, &pin_PH14), + PERIPH(8, 12, &pin_PI00), + PERIPH(7, 12, &pin_PH02), + PERIPH(7, 12, &pin_PH03), + PERIPH(5, 12, &pin_PF02), + PERIPH(5, 12, &pin_PF01), + PERIPH(6, 12, &pin_PG08), + PERIPH(5, 12, &pin_PF03), + PERIPH(5, 12, &pin_PF04), + PERIPH(7, 12, &pin_PH05), + PERIPH(5, 12, &pin_PF05), + PERIPH(7, 12, &pin_PH12), + PERIPH(6, 12, &pin_PG05), + PERIPH(6, 12, &pin_PG04), + PERIPH(7, 12, &pin_PH11), + PERIPH(7, 12, &pin_PH10), + PERIPH(3, 12, &pin_PD15), + PERIPH(6, 12, &pin_PG02), + PERIPH(6, 12, &pin_PG01), + PERIPH(7, 12, &pin_PH08), + PERIPH(7, 12, &pin_PH09), + PERIPH(3, 12, &pin_PD14), + PERIPH(5, 12, &pin_PF13), + PERIPH(6, 12, &pin_PG00), + PERIPH(4, 12, &pin_PE13), + PERIPH(3, 12, &pin_PD10), + PERIPH(5, 12, &pin_PF12), + PERIPH(5, 12, &pin_PF15), + PERIPH(4, 12, &pin_PE08), + PERIPH(4, 12, &pin_PE09), + PERIPH(4, 12, &pin_PE11), + PERIPH(4, 12, &pin_PE14), + PERIPH(3, 12, &pin_PD09), + PERIPH(3, 12, &pin_PD08), + PERIPH(5, 12, &pin_PF11), + PERIPH(5, 12, &pin_PF14), + PERIPH(4, 12, &pin_PE07), + PERIPH(4, 12, &pin_PE10), + PERIPH(4, 12, &pin_PE12), + PERIPH(4, 12, &pin_PE15), }; diff --git a/ports/stm/peripherals/stm32h7/stm32h750xx/periph.h b/ports/stm/peripherals/stm32h7/stm32h750xx/periph.h index f2cb1c2524e1a..f90f55071804d 100644 --- a/ports/stm/peripherals/stm32h7/stm32h750xx/periph.h +++ b/ports/stm/peripherals/stm32h7/stm32h750xx/periph.h @@ -7,26 +7,39 @@ #pragma once // I2C -extern I2C_TypeDef *mcu_i2c_banks[4]; +extern I2C_TypeDef *mcu_i2c_banks[MAX_I2C]; extern const mcu_periph_obj_t mcu_i2c_sda_list[12]; extern const mcu_periph_obj_t mcu_i2c_scl_list[12]; // SPI -extern SPI_TypeDef *mcu_spi_banks[6]; +extern SPI_TypeDef *mcu_spi_banks[MAX_SPI]; -extern const mcu_periph_obj_t mcu_spi_sck_list[19]; -extern const mcu_periph_obj_t mcu_spi_mosi_list[19]; -extern const mcu_periph_obj_t mcu_spi_miso_list[16]; +extern const mcu_periph_obj_t mcu_spi_sck_list[18]; +extern const mcu_periph_obj_t mcu_spi_mosi_list[18]; +extern const mcu_periph_obj_t mcu_spi_miso_list[15]; // UART extern USART_TypeDef *mcu_uart_banks[MAX_UART]; extern bool mcu_uart_has_usart[MAX_UART]; -extern const mcu_periph_obj_t mcu_uart_tx_list[25]; -extern const mcu_periph_obj_t mcu_uart_rx_list[26]; +extern const mcu_periph_obj_t mcu_uart_tx_list[24]; +extern const mcu_periph_obj_t mcu_uart_rx_list[25]; // Timers -#define TIM_BANK_ARRAY_LEN 14 -#define TIM_PIN_ARRAY_LEN 58 +#define TIM_PIN_ARRAY_LEN 65 +extern const mcu_tim_pin_obj_t mcu_tim_pin_list[TIM_PIN_ARRAY_LEN]; +#define TIM_BANK_ARRAY_LEN 17 extern TIM_TypeDef *mcu_tim_banks[TIM_BANK_ARRAY_LEN]; + +// SDIO - H750 has a MMC interface that includes SDIO +extern SDMMC_TypeDef *mcu_sdio_banks[1]; + +extern const mcu_periph_obj_t mcu_sdio_clock_list[1]; +extern const mcu_periph_obj_t mcu_sdio_command_list[1]; +extern const mcu_periph_obj_t mcu_sdio_data0_list[1]; +extern const mcu_periph_obj_t mcu_sdio_data1_list[1]; +extern const mcu_periph_obj_t mcu_sdio_data2_list[1]; +extern const mcu_periph_obj_t mcu_sdio_data3_list[1]; +// SDRam +extern const mcu_periph_obj_t sdram_pin_list[57]; diff --git a/ports/stm/peripherals/timers.c b/ports/stm/peripherals/timers.c index 9d963487a04d1..e8bebe5f5dfb4 100644 --- a/ports/stm/peripherals/timers.c +++ b/ports/stm/peripherals/timers.c @@ -5,14 +5,16 @@ // SPDX-License-Identifier: MIT #include "timers.h" -#include "py/mpconfig.h" #include "py/obj.h" #include "py/runtime.h" +#include "ports/stm/peripherals/periph.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" +#ifdef STM32H7 +#include "stm32h7xx_hal_rcc.h" +#endif -#if !(CPY_STM32H7) #define ALL_CLOCKS 0xFFFF #define NULL_IRQ 0xFF @@ -161,17 +163,29 @@ uint32_t stm_peripherals_timer_get_source_freq(TIM_TypeDef *timer) { // TIM{1,8,9,10,11} are on APB2 source = HAL_RCC_GetPCLK2Freq(); // 0b0xx means not divided; 0b100 is divide by 2; 0b101 by 4; 0b110 by 8; 0b111 by 16. + #ifdef STM32H7 + clk_div = (RCC->CFGR & RCC_D2CFGR_D2PPRE2); + #else clk_div = (RCC->CFGR & RCC_CFGR_PPRE2) >> RCC_CFGR_PPRE2_Pos; + #endif } else { // TIM{2,3,4,5,6,7,12,13,14} are on APB1 source = HAL_RCC_GetPCLK1Freq(); // 0b0xx means not divided; 0b100 is divide by 2; 0b101 by 4; 0b110 by 8; 0b111 by 16. + #ifdef STM32H7 + clk_div = (RCC->CFGR & RCC_D1CFGR_D1PPRE_Msk); + #else clk_div = (RCC->CFGR & RCC_CFGR_PPRE1) >> RCC_CFGR_PPRE1_Pos; + #endif } // Only some STM32's have TIMPRE. #if defined(RCC_CFGR_TIMPRE) + #ifdef STM32H7 + uint32_t timpre = RCC->CFGR & RCC_CFGR_TIMPRE; + #else uint32_t timpre = RCC->DCKCFGR & RCC_CFGR_TIMPRE; + #endif if (timpre == 0) { if (clk_div >= 0b100) { source *= 2; @@ -287,7 +301,7 @@ size_t stm_peripherals_timer_get_index(TIM_TypeDef *instance) { return ~(size_t)0; } -void tim_clock_enable(uint16_t mask) { +void tim_clock_enable(uint32_t mask) { #ifdef TIM1 if (mask & (1 << 0)) { __HAL_RCC_TIM1_CLK_ENABLE(); @@ -349,9 +363,28 @@ void tim_clock_enable(uint16_t mask) { __HAL_RCC_TIM14_CLK_ENABLE(); } #endif + + #ifdef STM32H750xx + // only enabled on the H750 board for now + #ifdef TIM15 + if (mask & (1 << 14)) { + __HAL_RCC_TIM15_CLK_ENABLE(); + } + #endif + #ifdef TIM16 + if (mask & (1 << 15)) { + __HAL_RCC_TIM16_CLK_ENABLE(); + } + #endif + #ifdef TIM17 + if (mask & (1 << 16)) { + __HAL_RCC_TIM17_CLK_ENABLE(); + } + #endif + #endif } -void tim_clock_disable(uint16_t mask) { +void tim_clock_disable(uint32_t mask) { #ifdef TIM1 if (mask & (1 << 0)) { __HAL_RCC_TIM1_CLK_DISABLE(); @@ -413,6 +446,26 @@ void tim_clock_disable(uint16_t mask) { __HAL_RCC_TIM14_CLK_DISABLE(); } #endif + + #ifdef STM32H750xx + // only enabled on the H750 board for now + #ifdef TIM15 + if (mask & (1 << 14)) { + __HAL_RCC_TIM15_CLK_DISABLE(); + } + #endif + #ifdef TIM16 + if (mask & (1 << 15)) { + __HAL_RCC_TIM16_CLK_DISABLE(); + } + #endif + #ifdef TIM17 + if (mask & (1 << 16)) { + __HAL_RCC_TIM17_CLK_DISABLE(); + } + #endif + #endif + } static void callback_router(size_t index) { @@ -421,75 +474,108 @@ static void callback_router(size_t index) { } } +#ifdef TIM1 void TIM1_CC_IRQHandler(void) { // Advanced timer callback_router(1); } +#endif +#ifdef TIM2 void TIM2_IRQHandler(void) { callback_router(2); } +#endif +#ifdef TIM3 void TIM3_IRQHandler(void) { callback_router(3); } +#endif +#ifdef TIM4 void TIM4_IRQHandler(void) { callback_router(4); } +#endif +#ifdef TIM5 void TIM5_IRQHandler(void) { callback_router(5); } +#endif +#ifdef TIM6 void TIM6_DAC_IRQHandler(void) { // Basic timer (DAC) callback_router(6); } +#endif +#ifdef TIM7 void TIM7_IRQHandler(void) { // Basic timer callback_router(7); } +#endif +#ifdef TIM8 void TIM8_CC_IRQHandler(void) { // Advanced timer callback_router(8); } +#endif // Advanced timer interrupts are currently unused. +#ifdef TIM9 void TIM1_BRK_TIM9_IRQHandler(void) { callback_router(9); } +#endif +#ifdef TIM10 void TIM1_UP_TIM10_IRQHandler(void) { callback_router(10); } +#endif +#ifdef TIM11 void TIM1_TRG_COM_TIM11_IRQHandler(void) { callback_router(11); } +#endif +#ifdef TIM12 void TIM8_BRK_TIM12_IRQHandler(void) { callback_router(12); } +#endif +#ifdef TIM13 void TIM8_UP_TIM13_IRQHandler(void) { callback_router(13); } +#endif +#ifdef TIM14 void TIM8_TRG_COM_TIM14_IRQHandler(void) { callback_router(14); } +#endif -#if (CPY_STM32H7) +#ifdef STM32H750xx +// only enabled on the H750 board for now +#ifdef TIM15 void TIM15_IRQHandler(void) { callback_router(15); } +#endif +#ifdef TIM16 void TIM16_IRQHandler(void) { callback_router(16); } +#endif +#ifdef TIM17 void TIM17_IRQHandler(void) { callback_router(17); } #endif - #endif diff --git a/ports/stm/peripherals/timers.h b/ports/stm/peripherals/timers.h index db3f9472e1e9c..00c198250cbd3 100644 --- a/ports/stm/peripherals/timers.h +++ b/ports/stm/peripherals/timers.h @@ -7,13 +7,12 @@ #pragma once #include -#include "py/mphal.h" -#include "peripherals/periph.h" +#include #include STM32_HAL_H -void tim_clock_enable(uint16_t mask); -void tim_clock_disable(uint16_t mask); +void tim_clock_enable(uint32_t mask); +void tim_clock_disable(uint32_t mask); uint32_t stm_peripherals_timer_get_source_freq(TIM_TypeDef *timer); size_t stm_peripherals_timer_get_irqnum(TIM_TypeDef *instance); void timers_reset(void); diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index 7743d82f6010e..3d43e7d4b2ad5 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -42,6 +42,16 @@ void NVIC_SystemReset(void) NORETURN; #if (CPY_STM32H7) || (CPY_STM32F7) +#ifdef STM32H750xx +// Assumes H750 board has external SDRAM -- currently Diasy Seed +// TODO: find a way to detect if SDRAM actually exists +#include "sdram.h" +#include +#include +#include "lib/tlsf/tlsf.h" + +#define CIRCUITPY_RAM_DEVICE_COUNT (2) +#endif // Device memories must be accessed in order. #define DEVICE 2 @@ -146,6 +156,16 @@ __attribute__((used, naked)) void Reset_Handler(void) { start execution of the firmware from the external flash. It also makes the SystemInit() call not necessary for this chip. */ + #if defined(__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U) + /* Enable I cache. */ + SCB_EnableICache(); + #endif /* __ICACHE_PRESENT */ + + #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) + /* Enable D cache. */ + SCB_EnableDCache(); + #endif /* __DCACHE_PRESENT */ + #else SystemInit(); #endif @@ -157,6 +177,63 @@ __attribute__((used, naked)) void Reset_Handler(void) { // Low power clock variables static volatile uint32_t systick_ms; +#ifdef STM32H750xx +static tlsf_t _heap = NULL; +static pool_t pools[CIRCUITPY_RAM_DEVICE_COUNT] = {NULL}; + + +void port_heap_init(void) { + // heap init in _port_heap_init called from port_init +} + +static void _port_heap_init(void) { + uint32_t *heap_bottom = port_heap_get_bottom(); + uint32_t *heap_top = port_heap_get_top(); + size_t size = (heap_top - heap_bottom) * sizeof(uint32_t); + #if defined(CIRCUITPY_HW_SDRAM_SIZE) && (CIRCUITPY_HW_SDRAM_SIZE != 0) + size_t sdram_memory_size = sdram_size(); + #else + size_t sdram_memory_size = 0; + #endif + _heap = tlsf_create_with_pool(heap_bottom, size, size + sdram_memory_size); + pools[0] = tlsf_get_pool(_heap); + #if defined(CIRCUITPY_HW_SDRAM_SIZE) && (CIRCUITPY_HW_SDRAM_SIZE != 0) + pools[1] = tlsf_add_pool(_heap, sdram_start(), sdram_memory_size); + #endif +} + +static bool max_size_walker(void *ptr, size_t size, int used, void *user) { + size_t *max_size = (size_t *)user; + if (!used && *max_size < size) { + *max_size = size; + } + return true; +} + +size_t port_heap_get_largest_free_size(void) { + size_t max_size = 0; + for (size_t i = 0; i < CIRCUITPY_RAM_DEVICE_COUNT; i++) { + if (pools[i]) { + tlsf_walk_pool(pools[i], max_size_walker, &max_size); + } + } + return tlsf_fit_size(_heap, max_size); +} + +void *port_malloc(size_t size, bool dma_capable) { + void *block = tlsf_malloc(_heap, size); + return block; +} + +void port_free(void *ptr) { + tlsf_free(_heap, ptr); +} + +void *port_realloc(void *ptr, size_t size) { + return tlsf_realloc(_heap, ptr, size); +} +#endif + safe_mode_t port_init(void) { HAL_Init(); // Turns on SysTick __HAL_RCC_SYSCFG_CLK_ENABLE(); @@ -190,6 +267,11 @@ safe_mode_t port_init(void) { __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); stm32_peripherals_rtc_reset_alarms(); + #ifdef STM32H750xx + sdram_init(); + // sdram_test(false); + _port_heap_init(); + #endif // Turn off SysTick SysTick->CTRL = 0; From 6ac1e5b34464f855d9e8a6edf45144a4a4e6ab17 Mon Sep 17 00:00:00 2001 From: snkymkrct Date: Wed, 2 Apr 2025 21:39:54 +0200 Subject: [PATCH 2/5] SDRAM code refactoring --- .../stm/boards/daisy_seed_with_sdram/board.c | 53 ++++- .../daisy_seed_with_sdram/mpconfigboard.h | 36 +--- ports/stm/peripherals/sdram.c | 188 +++++------------- ports/stm/peripherals/sdram.h | 32 ++- ports/stm/supervisor/port.c | 25 +-- 5 files changed, 151 insertions(+), 183 deletions(-) diff --git a/ports/stm/boards/daisy_seed_with_sdram/board.c b/ports/stm/boards/daisy_seed_with_sdram/board.c index 9cf9b4a48a7b7..b2f89f1680338 100644 --- a/ports/stm/boards/daisy_seed_with_sdram/board.c +++ b/ports/stm/boards/daisy_seed_with_sdram/board.c @@ -3,7 +3,58 @@ // SPDX-FileCopyrightText: Copyright (c) 2024 snkYmkrct // // SPDX-License-Identifier: MIT +#include STM32_HAL_H #include "supervisor/board.h" +#include "sdram.h" -// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. +extern void port_add_sdram_to_heap(void); + +/** SDRAM banks configuration. */ +static const struct stm32_sdram_bank_config bank_config[] = { + { .init = { + .SDBank = FMC_SDRAM_BANK1, + .ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9, + .RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13, + .MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_32, + .InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4, + .CASLatency = FMC_SDRAM_CAS_LATENCY_3, + .WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE, + .SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2, + .ReadBurst = FMC_SDRAM_RBURST_ENABLE, + .ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0 + }, + .timing = { + .LoadToActiveDelay = 2, + .ExitSelfRefreshDelay = 8, + .SelfRefreshTime = 5, + .RowCycleDelay = 6, + .WriteRecoveryTime = 3, + .RPDelay = 2, + .RCDDelay = 2 + }} +}; + +/* SDRAM configuration. */ +static const struct stm32_sdram_config config = { + .sdram = FMC_SDRAM_DEVICE, + .power_up_delay = 0, + .num_auto_refresh = 8, + .mode_register = SDRAM_MODEREG_BURST_LENGTH_4 | + SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | + SDRAM_MODEREG_CAS_LATENCY_3 | + SDRAM_MODEREG_WRITEBURST_MODE_SINGLE, + /* Set the device refresh rate based on the RM0433 STM reference manual + refresh_rate = [(SDRAM self refresh time / number of rows) x SDRAM CLK] – 20 + = [(64ms/8192) * 100MHz] - 20 = 781.25 - 20 + */ + .refresh_rate = (64 * 100000 / 8192 - 20), + .banks = bank_config, + .banks_len = 1, +}; + +void board_init(void) { + sdram_init(&config); +// sdram_test(true); + port_add_sdram_to_heap(); +} diff --git a/ports/stm/boards/daisy_seed_with_sdram/mpconfigboard.h b/ports/stm/boards/daisy_seed_with_sdram/mpconfigboard.h index 2cc74edd07be5..4951072d9100b 100644 --- a/ports/stm/boards/daisy_seed_with_sdram/mpconfigboard.h +++ b/ports/stm/boards/daisy_seed_with_sdram/mpconfigboard.h @@ -32,39 +32,9 @@ // for RNG not audio #define CPY_CLK_USB_USES_AUDIOPLL (1) -// SDRAM -- on FMC controller - -#define CPY_SDRAM_REGION MPU_REGION_NUMBER10 -#define CPY_SDRAM_REGION_SIZE MPU_REGION_SIZE_64MB - -#define CIRCUITPY_HW_FMC_SDCKE0 -#define CIRCUITPY_HW_FMC_SDNE0 +// SDRAM and MPU region #define CIRCUITPY_HW_SDRAM_SIZE (64 * 1024 * 1024) // 64 MByte -#define CIRCUITPY_HW_SDRAM_STARTUP_TEST (1) -#define CIRCUITPY_HW_FMC_SWAP_BANKS (0) - -#define CIRCUITPY_HW_SDRAM_CLOCK_PERIOD 2 -#define CIRCUITPY_HW_SDRAM_CAS_LATENCY 3 -#define CIRCUITPY_HW_SDRAM_FREQUENCY_KHZ (100000) // 100 MHz -#define CIRCUITPY_HW_SDRAM_TIMING_TMRD (2) -#define CIRCUITPY_HW_SDRAM_TIMING_TXSR (8) -#define CIRCUITPY_HW_SDRAM_TIMING_TRAS (5) -#define CIRCUITPY_HW_SDRAM_TIMING_TRC (6) -#define CIRCUITPY_HW_SDRAM_TIMING_TWR (3) -#define CIRCUITPY_HW_SDRAM_TIMING_TRP (2) -#define CIRCUITPY_HW_SDRAM_TIMING_TRCD (2) -#define CIRCUITPY_HW_SDRAM_ROW_BITS_NUM 13 -#define CIRCUITPY_HW_SDRAM_MEM_BUS_WIDTH 32 -#define CIRCUITPY_HW_SDRAM_REFRESH_CYCLES 8192 - -#define CIRCUITPY_HW_SDRAM_COLUMN_BITS_NUM 9 -#define CIRCUITPY_HW_SDRAM_INTERN_BANKS_NUM 4 -#define CIRCUITPY_HW_SDRAM_RPIPE_DELAY 0 -#define CIRCUITPY_HW_SDRAM_RBURST (1) -#define CIRCUITPY_HW_SDRAM_WRITE_PROTECTION (0) - -#define CIRCUITPY_HW_SDRAM_AUTOREFRESH_NUM (8) -#define CIRCUITPY_HW_SDRAM_BURST_LENGTH 4 -#define CIRCUITPY_HW_SDRAM_REFRESH_RATE (64) // ms +#define CPY_SDRAM_REGION MPU_REGION_NUMBER10 +#define CPY_SDRAM_REGION_SIZE MPU_REGION_SIZE_64MB diff --git a/ports/stm/peripherals/sdram.c b/ports/stm/peripherals/sdram.c index 159d14c410295..4d05267794bbd 100644 --- a/ports/stm/peripherals/sdram.c +++ b/ports/stm/peripherals/sdram.c @@ -6,6 +6,7 @@ // // SPDX-License-Identifier: MIT +#include #include #include #include @@ -35,46 +36,17 @@ #define DEBUG_OP_printf(...) (void)0 #endif -#define SDRAM_TIMEOUT ((uint32_t)0xFFFF) -#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000) -#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001) -#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002) -#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004) -#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000) -#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008) -#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020) -#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030) -#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000) -#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000) -#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) - -#if defined(CIRCUITPY_HW_FMC_SDCKE0) && defined(CIRCUITPY_HW_FMC_SDNE0) -#define FMC_SDRAM_BANK FMC_SDRAM_BANK1 -#define FMC_SDRAM_CMD_TARGET_BANK FMC_SDRAM_CMD_TARGET_BANK1 -#if CIRCUITPY_HW_FMC_SWAP_BANKS -#define SDRAM_START_ADDRESS 0x60000000 -#else -#define SDRAM_START_ADDRESS 0xC0000000 -#endif -#elif defined(CIRCUITPY_HW_FMC_SDCKE1) && defined(CIRCUITPY_HW_FMC_SDNE1) -#define FMC_SDRAM_BANK FMC_SDRAM_BANK2 -#define FMC_SDRAM_CMD_TARGET_BANK FMC_SDRAM_CMD_TARGET_BANK2 -#if CIRCUITPY_HW_FMC_SWAP_BANKS -#define SDRAM_START_ADDRESS 0x70000000 -#else -#define SDRAM_START_ADDRESS 0xD0000000 -#endif -#endif - -#ifdef FMC_SDRAM_BANK +#define SDRAM_TIMEOUT ((uint32_t)0xFFFF) +#define CIRCUITPY_HW_SDRAM_STARTUP_TEST (0) static uint8_t FMC_Initialized = 0; static SDRAM_HandleTypeDef hsdram = {0}; +static uint32_t sdram_start_address = 0; -static void sdram_init_seq(void); +static void sdram_init_seq(const struct stm32_sdram_config *config); -bool sdram_init(void) { +void sdram_init(const struct stm32_sdram_config *config) { FMC_SDRAM_TimingTypeDef SDRAM_Timing = {0}; if (!FMC_Initialized) { @@ -91,65 +63,37 @@ bool sdram_init(void) { /* Peripheral clock enable */ __HAL_RCC_FMC_CLK_ENABLE(); FMC_Initialized = 1; + for (uint i = 0; i < MP_ARRAY_SIZE(sdram_pin_list); i++) { + GPIO_InitTypeDef GPIO_InitStruct = {0}; + GPIO_InitStruct.Pin = pin_mask(sdram_pin_list[i].pin->number); + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF12_FMC; + HAL_GPIO_Init(pin_port(sdram_pin_list[i].pin->port), &GPIO_InitStruct); + never_reset_pin_number(sdram_pin_list[i].pin->port, sdram_pin_list[i].pin->number); + } } - #if CIRCUITPY_HW_FMC_SWAP_BANKS - HAL_SetFMCMemorySwappingConfig(FMC_SWAPBMAP_SDRAM_SRAM); - #endif - - for (uint i = 0; i < MP_ARRAY_SIZE(sdram_pin_list); i++) { - GPIO_InitTypeDef GPIO_InitStruct = {0}; - GPIO_InitStruct.Pin = pin_mask(sdram_pin_list[i].pin->number); - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF12_FMC; - HAL_GPIO_Init(pin_port(sdram_pin_list[i].pin->port), &GPIO_InitStruct); - never_reset_pin_number(sdram_pin_list[i].pin->port, sdram_pin_list[i].pin->number); - } /* SDRAM device configuration */ - hsdram.Instance = FMC_SDRAM_DEVICE; - /* Timing configuration for 90 Mhz of SD clock frequency (180Mhz/2) */ - /* TMRD: 2 Clock cycles */ - SDRAM_Timing.LoadToActiveDelay = CIRCUITPY_HW_SDRAM_TIMING_TMRD; - /* TXSR: min=70ns (6x11.90ns) */ - SDRAM_Timing.ExitSelfRefreshDelay = CIRCUITPY_HW_SDRAM_TIMING_TXSR; - /* TRAS */ - SDRAM_Timing.SelfRefreshTime = CIRCUITPY_HW_SDRAM_TIMING_TRAS; - /* TRC */ - SDRAM_Timing.RowCycleDelay = CIRCUITPY_HW_SDRAM_TIMING_TRC; - /* TWR */ - SDRAM_Timing.WriteRecoveryTime = CIRCUITPY_HW_SDRAM_TIMING_TWR; - /* TRP */ - SDRAM_Timing.RPDelay = CIRCUITPY_HW_SDRAM_TIMING_TRP; - /* TRCD */ - SDRAM_Timing.RCDDelay = CIRCUITPY_HW_SDRAM_TIMING_TRCD; - - #define _FMC_INIT(x, n) x##_##n - #define FMC_INIT(x, n) _FMC_INIT(x, n) - - hsdram.Init.SDBank = FMC_SDRAM_BANK; - hsdram.Init.ColumnBitsNumber = FMC_INIT(FMC_SDRAM_COLUMN_BITS_NUM, CIRCUITPY_HW_SDRAM_COLUMN_BITS_NUM); - hsdram.Init.RowBitsNumber = FMC_INIT(FMC_SDRAM_ROW_BITS_NUM, CIRCUITPY_HW_SDRAM_ROW_BITS_NUM); - hsdram.Init.MemoryDataWidth = FMC_INIT(FMC_SDRAM_MEM_BUS_WIDTH, CIRCUITPY_HW_SDRAM_MEM_BUS_WIDTH); - hsdram.Init.InternalBankNumber = FMC_INIT(FMC_SDRAM_INTERN_BANKS_NUM, CIRCUITPY_HW_SDRAM_INTERN_BANKS_NUM); - hsdram.Init.CASLatency = FMC_INIT(FMC_SDRAM_CAS_LATENCY, CIRCUITPY_HW_SDRAM_CAS_LATENCY); - hsdram.Init.SDClockPeriod = FMC_INIT(FMC_SDRAM_CLOCK_PERIOD, CIRCUITPY_HW_SDRAM_CLOCK_PERIOD); - hsdram.Init.ReadPipeDelay = FMC_INIT(FMC_SDRAM_RPIPE_DELAY, CIRCUITPY_HW_SDRAM_RPIPE_DELAY); - hsdram.Init.ReadBurst = (CIRCUITPY_HW_SDRAM_RBURST) ? FMC_SDRAM_RBURST_ENABLE : FMC_SDRAM_RBURST_DISABLE; - hsdram.Init.WriteProtection = (CIRCUITPY_HW_SDRAM_WRITE_PROTECTION) ? FMC_SDRAM_WRITE_PROTECTION_ENABLE : FMC_SDRAM_WRITE_PROTECTION_DISABLE; - - /* Initialize the SDRAM controller */ - if (HAL_SDRAM_Init(&hsdram, &SDRAM_Timing) != HAL_OK) { - DEBUG_printf("sdram: %s", "init error"); - return false; + hsdram.Instance = config->sdram; + + for (size_t i = 0U; i < config->banks_len; i++) { + hsdram.State = HAL_SDRAM_STATE_RESET; + + memcpy(&hsdram.Init, &config->banks[i].init, sizeof(hsdram.Init)); + + memcpy(&SDRAM_Timing, &config->banks[i].timing, sizeof(SDRAM_Timing)); + + /* Initialize the SDRAM controller */ + if (HAL_SDRAM_Init(&hsdram, &SDRAM_Timing) != HAL_OK) { + DEBUG_printf("sdram bank[%d]: %s", i, "init error"); + } } - sdram_init_seq(); + sdram_init_seq(config); - return true; } - void sdram_deinit(void) { FMC_SDRAM_CommandTypeDef command = {0}; if (FMC_Initialized) { @@ -167,78 +111,55 @@ void sdram_deinit(void) { } void *sdram_start(void) { - return (void *)SDRAM_START_ADDRESS; + return (void *)sdram_start_address; } void *sdram_end(void) { - return (void *)(SDRAM_START_ADDRESS + CIRCUITPY_HW_SDRAM_SIZE); + return (void *)(sdram_start_address + CIRCUITPY_HW_SDRAM_SIZE); } uint32_t sdram_size(void) { return CIRCUITPY_HW_SDRAM_SIZE; } -static void sdram_init_seq(void) { +static void sdram_init_seq(const struct stm32_sdram_config *config) { FMC_SDRAM_CommandTypeDef command = {0}; /* Program the SDRAM external device */ - __IO uint32_t tmpmrd = 0; + + command.AutoRefreshNumber = config->num_auto_refresh; + command.ModeRegisterDefinition = config->mode_register; + if (config->banks_len == 2U) { + command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2; + sdram_start_address = 0xC0000000; + } else if (config->banks[0].init.SDBank == FMC_SDRAM_BANK1) { + command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + sdram_start_address = 0xC0000000; + } else { + command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2; + sdram_start_address = 0xD0000000; + + } /* Configure a clock configuration enable command */ command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; - command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK; - command.AutoRefreshNumber = 1; - command.ModeRegisterDefinition = 0; - - /* Send the command */ HAL_SDRAM_SendCommand(&hsdram, &command, HAL_MAX_DELAY); - /* Insert 100 ms delay */ HAL_Delay(100); /* Configure a PALL (precharge all) command */ command.CommandMode = FMC_SDRAM_CMD_PALL; - command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK; - command.AutoRefreshNumber = 1; - command.ModeRegisterDefinition = 0; - - /* Send the command */ HAL_SDRAM_SendCommand(&hsdram, &command, HAL_MAX_DELAY); /* Configure a Auto-Refresh command */ command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; - command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK; - command.AutoRefreshNumber = CIRCUITPY_HW_SDRAM_AUTOREFRESH_NUM; - command.ModeRegisterDefinition = 0; - - /* Send the command */ HAL_SDRAM_SendCommand(&hsdram, &command, HAL_MAX_DELAY); - /* Program the external memory mode register */ - tmpmrd = (uint32_t)0x0 | FMC_INIT(SDRAM_MODEREG_BURST_LENGTH, CIRCUITPY_HW_SDRAM_BURST_LENGTH) | - SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | - FMC_INIT(SDRAM_MODEREG_CAS_LATENCY, CIRCUITPY_HW_SDRAM_CAS_LATENCY) | - SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; - command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; - command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK; - command.AutoRefreshNumber = 1; - command.ModeRegisterDefinition = tmpmrd; - - /* Send the command */ + /* load mode */ HAL_SDRAM_SendCommand(&hsdram, &command, HAL_MAX_DELAY); - /* Set the refresh rate counter. - Assuming 100MHz frequency, 8192 refresh cycles and 64ms refresh rate: - RefreshRate = 64 ms / 8192 cyc = 7.8125 us/cyc - RefreshCycles = 7.8125 us * 100 MHz = 782 - According to the formula on p.1665 of the reference manual, - we also need to subtract 20 from the value, so the target - refresh rate is 782 - 20 = 762 - */ - - #define REFRESH_COUNT (CIRCUITPY_HW_SDRAM_REFRESH_RATE * CIRCUITPY_HW_SDRAM_FREQUENCY_KHZ / CIRCUITPY_HW_SDRAM_REFRESH_CYCLES - 20) - - HAL_SDRAM_ProgramRefreshRate(&hsdram, REFRESH_COUNT); + /* program refresh count */ + HAL_SDRAM_ProgramRefreshRate(&hsdram, config->refresh_rate); #if defined(STM32F7) || defined(STM32H7) __disable_irq(); @@ -247,7 +168,7 @@ static void sdram_init_seq(void) { */ MPU_InitStruct.Enable = MPU_REGION_ENABLE; MPU_InitStruct.Number = CPY_SDRAM_REGION; - MPU_InitStruct.BaseAddress = SDRAM_START_ADDRESS; + MPU_InitStruct.BaseAddress = sdram_start_address; MPU_InitStruct.Size = CPY_SDRAM_REGION_SIZE; MPU_InitStruct.SubRegionDisable = 0x0; MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; @@ -267,6 +188,8 @@ static void sdram_init_seq(void) { } +#if defined(CIRCUITPY_HW_SDRAM_STARTUP_TEST) && (CIRCUITPY_HW_SDRAM_STARTUP_TEST == 1) + bool __attribute__((optimize("Os"))) sdram_test(bool exhaustive) { uint8_t const pattern = 0xaa; uint8_t const antipattern = 0x55; @@ -293,7 +216,7 @@ bool __attribute__((optimize("Os"))) sdram_test(bool exhaustive) { #endif // Test data bus - for (uint32_t i = 0; i < CIRCUITPY_HW_SDRAM_MEM_BUS_WIDTH; i++) { + for (uint32_t i = 0; i < hsdram.Init.MemoryDataWidth; i++) { *((volatile uint32_t *)mem_base) = (1u << i); __DSB(); if (*((volatile uint32_t *)mem_base) != (1u << i)) { @@ -367,5 +290,4 @@ bool __attribute__((optimize("Os"))) sdram_test(bool exhaustive) { return true; } - -#endif // FMC_SDRAM_BANK +#endif // sdram_test diff --git a/ports/stm/peripherals/sdram.h b/ports/stm/peripherals/sdram.h index 1f5b1a4520d4e..46343b6861e43 100644 --- a/ports/stm/peripherals/sdram.h +++ b/ports/stm/peripherals/sdram.h @@ -6,10 +6,40 @@ #pragma once +#include "stm32h7xx_ll_fmc.h" #include #include -bool sdram_init(void); +#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001) +#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002) +#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004) +#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008) +#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020) +#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030) +#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) + +/** FMC SDRAM controller bank configuration fields. */ +struct stm32_sdram_bank_config { + FMC_SDRAM_InitTypeDef init; + FMC_SDRAM_TimingTypeDef timing; +}; + +/** FMC SDRAM controller configuration fields. */ +struct stm32_sdram_config { + FMC_SDRAM_TypeDef *sdram; + uint32_t power_up_delay; + uint8_t num_auto_refresh; + uint16_t mode_register; + uint16_t refresh_rate; + const struct stm32_sdram_bank_config *banks; + size_t banks_len; +}; + +void sdram_init(const struct stm32_sdram_config *config); void sdram_deinit(void); void *sdram_start(void); void *sdram_end(void); diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index 3d43e7d4b2ad5..f55bdd18fbb28 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -42,14 +42,12 @@ void NVIC_SystemReset(void) NORETURN; #if (CPY_STM32H7) || (CPY_STM32F7) -#ifdef STM32H750xx -// Assumes H750 board has external SDRAM -- currently Diasy Seed -// TODO: find a way to detect if SDRAM actually exists +#if defined(CIRCUITPY_HW_SDRAM_SIZE) #include "sdram.h" #include #include #include "lib/tlsf/tlsf.h" - +// internal SRAM + external SDRAM #define CIRCUITPY_RAM_DEVICE_COUNT (2) #endif @@ -177,7 +175,7 @@ __attribute__((used, naked)) void Reset_Handler(void) { // Low power clock variables static volatile uint32_t systick_ms; -#ifdef STM32H750xx +#if defined(CIRCUITPY_HW_SDRAM_SIZE) static tlsf_t _heap = NULL; static pool_t pools[CIRCUITPY_RAM_DEVICE_COUNT] = {NULL}; @@ -186,20 +184,19 @@ void port_heap_init(void) { // heap init in _port_heap_init called from port_init } +void port_add_sdram_to_heap(void) { + size_t sdram_memory_size = sdram_size(); + pools[1] = tlsf_add_pool(_heap, sdram_start(), sdram_memory_size); +} + static void _port_heap_init(void) { uint32_t *heap_bottom = port_heap_get_bottom(); uint32_t *heap_top = port_heap_get_top(); size_t size = (heap_top - heap_bottom) * sizeof(uint32_t); - #if defined(CIRCUITPY_HW_SDRAM_SIZE) && (CIRCUITPY_HW_SDRAM_SIZE != 0) size_t sdram_memory_size = sdram_size(); - #else - size_t sdram_memory_size = 0; - #endif + _heap = tlsf_create_with_pool(heap_bottom, size, size + sdram_memory_size); pools[0] = tlsf_get_pool(_heap); - #if defined(CIRCUITPY_HW_SDRAM_SIZE) && (CIRCUITPY_HW_SDRAM_SIZE != 0) - pools[1] = tlsf_add_pool(_heap, sdram_start(), sdram_memory_size); - #endif } static bool max_size_walker(void *ptr, size_t size, int used, void *user) { @@ -267,9 +264,7 @@ safe_mode_t port_init(void) { __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); stm32_peripherals_rtc_reset_alarms(); - #ifdef STM32H750xx - sdram_init(); - // sdram_test(false); + #if defined(CIRCUITPY_HW_SDRAM_SIZE) _port_heap_init(); #endif // Turn off SysTick From f72fffd3476d782f61024de4da894a29371c2ef9 Mon Sep 17 00:00:00 2001 From: snkymkrct Date: Mon, 7 Apr 2025 09:30:47 +0200 Subject: [PATCH 3/5] function rename _add_sdram_to_heap and small refactoring --- ports/stm/boards/daisy_seed_with_sdram/board.c | 6 +++--- ports/stm/peripherals/sdram.c | 2 +- ports/stm/supervisor/port.c | 3 ++- ports/stm/supervisor/stm.h | 10 ++++++++++ 4 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 ports/stm/supervisor/stm.h diff --git a/ports/stm/boards/daisy_seed_with_sdram/board.c b/ports/stm/boards/daisy_seed_with_sdram/board.c index b2f89f1680338..f135bcbc2e0ab 100644 --- a/ports/stm/boards/daisy_seed_with_sdram/board.c +++ b/ports/stm/boards/daisy_seed_with_sdram/board.c @@ -6,9 +6,9 @@ #include STM32_HAL_H #include "supervisor/board.h" +#include "supervisor/stm.h" #include "sdram.h" -extern void port_add_sdram_to_heap(void); /** SDRAM banks configuration. */ static const struct stm32_sdram_bank_config bank_config[] = { @@ -38,7 +38,7 @@ static const struct stm32_sdram_bank_config bank_config[] = { /* SDRAM configuration. */ static const struct stm32_sdram_config config = { .sdram = FMC_SDRAM_DEVICE, - .power_up_delay = 0, + .power_up_delay = 100, .num_auto_refresh = 8, .mode_register = SDRAM_MODEREG_BURST_LENGTH_4 | SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | @@ -56,5 +56,5 @@ static const struct stm32_sdram_config config = { void board_init(void) { sdram_init(&config); // sdram_test(true); - port_add_sdram_to_heap(); + stm_add_sdram_to_heap(); } diff --git a/ports/stm/peripherals/sdram.c b/ports/stm/peripherals/sdram.c index 4d05267794bbd..6179197fa95c9 100644 --- a/ports/stm/peripherals/sdram.c +++ b/ports/stm/peripherals/sdram.c @@ -144,7 +144,7 @@ static void sdram_init_seq(const struct stm32_sdram_config *config) { command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; HAL_SDRAM_SendCommand(&hsdram, &command, HAL_MAX_DELAY); - HAL_Delay(100); + HAL_Delay(config->power_up_delay); /* Configure a PALL (precharge all) command */ command.CommandMode = FMC_SDRAM_CMD_PALL; diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index f55bdd18fbb28..5f29eaaf9625a 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -43,6 +43,7 @@ void NVIC_SystemReset(void) NORETURN; #if (CPY_STM32H7) || (CPY_STM32F7) #if defined(CIRCUITPY_HW_SDRAM_SIZE) +#include "stm.h" #include "sdram.h" #include #include @@ -184,7 +185,7 @@ void port_heap_init(void) { // heap init in _port_heap_init called from port_init } -void port_add_sdram_to_heap(void) { +void stm_add_sdram_to_heap(void) { size_t sdram_memory_size = sdram_size(); pools[1] = tlsf_add_pool(_heap, sdram_start(), sdram_memory_size); } diff --git a/ports/stm/supervisor/stm.h b/ports/stm/supervisor/stm.h new file mode 100644 index 0000000000000..6d3342137fb98 --- /dev/null +++ b/ports/stm/supervisor/stm.h @@ -0,0 +1,10 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 snkYmkrct +// +// SPDX-License-Identifier: MIT + +#pragma once + + +void stm_add_sdram_to_heap(void); From e3c4aebb67633a57f1ea607207c666531ccf4bc1 Mon Sep 17 00:00:00 2001 From: snkymkrct Date: Mon, 7 Apr 2025 09:49:49 +0200 Subject: [PATCH 4/5] Fix NULL pointer exception in audiopwmio active_audio was set to NULL, but then used in the following set_pin() call. because of MPU, this triggered hard fault on the stm32h7. --- ports/stm/common-hal/audiopwmio/PWMAudioOut.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/stm/common-hal/audiopwmio/PWMAudioOut.c b/ports/stm/common-hal/audiopwmio/PWMAudioOut.c index 475f3beded8a3..2099f8d36bf2c 100644 --- a/ports/stm/common-hal/audiopwmio/PWMAudioOut.c +++ b/ports/stm/common-hal/audiopwmio/PWMAudioOut.c @@ -342,7 +342,6 @@ void common_hal_audiopwmio_pwmaudioout_stop(audiopwmio_pwmaudioout_obj_t *self) tim_handle.Instance->CR1 &= ~TIM_CR1_CEN; stm_peripherals_timer_free(tim_handle.Instance); - active_audio = NULL; self->stopping = false; self->paused = false; @@ -352,6 +351,8 @@ void common_hal_audiopwmio_pwmaudioout_stop(audiopwmio_pwmaudioout_obj_t *self) set_pin(1, GPIO_PIN_RESET); } + active_audio = NULL; + // Cannot free buffers here because we may be called from // the interrupt handler, and the heap is not reentrant. } From 330480d58c9c141360fd5721e7a6f6c1d5d4c513 Mon Sep 17 00:00:00 2001 From: snkymkrct Date: Mon, 7 Apr 2025 09:57:50 +0200 Subject: [PATCH 5/5] fix for peripheral clock read on stm32h7 --- ports/stm/peripherals/timers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/stm/peripherals/timers.c b/ports/stm/peripherals/timers.c index e8bebe5f5dfb4..25cb9efcde03e 100644 --- a/ports/stm/peripherals/timers.c +++ b/ports/stm/peripherals/timers.c @@ -164,7 +164,7 @@ uint32_t stm_peripherals_timer_get_source_freq(TIM_TypeDef *timer) { source = HAL_RCC_GetPCLK2Freq(); // 0b0xx means not divided; 0b100 is divide by 2; 0b101 by 4; 0b110 by 8; 0b111 by 16. #ifdef STM32H7 - clk_div = (RCC->CFGR & RCC_D2CFGR_D2PPRE2); + clk_div = (RCC->D2CFGR & RCC_D2CFGR_D2PPRE2) >> RCC_D2CFGR_D2PPRE2_Pos; #else clk_div = (RCC->CFGR & RCC_CFGR_PPRE2) >> RCC_CFGR_PPRE2_Pos; #endif @@ -173,7 +173,7 @@ uint32_t stm_peripherals_timer_get_source_freq(TIM_TypeDef *timer) { source = HAL_RCC_GetPCLK1Freq(); // 0b0xx means not divided; 0b100 is divide by 2; 0b101 by 4; 0b110 by 8; 0b111 by 16. #ifdef STM32H7 - clk_div = (RCC->CFGR & RCC_D1CFGR_D1PPRE_Msk); + clk_div = (RCC->D1CFGR & RCC_D1CFGR_D1PPRE) >> RCC_D1CFGR_D1PPRE_Pos; #else clk_div = (RCC->CFGR & RCC_CFGR_PPRE1) >> RCC_CFGR_PPRE1_Pos; #endif