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/board.c b/ports/stm/boards/daisy_seed_with_sdram/board.c index 9cf9b4a48a7b7..f135bcbc2e0ab 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 "supervisor/stm.h" +#include "sdram.h" -// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. + +/** 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 = 100, + .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); + stm_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 f0af0a0732b60..4951072d9100b 100644 --- a/ports/stm/boards/daisy_seed_with_sdram/mpconfigboard.h +++ b/ports/stm/boards/daisy_seed_with_sdram/mpconfigboard.h @@ -31,3 +31,10 @@ // for RNG not audio #define CPY_CLK_USB_USES_AUDIOPLL (1) + +// SDRAM and MPU region + +#define CIRCUITPY_HW_SDRAM_SIZE (64 * 1024 * 1024) // 64 MByte + +#define CPY_SDRAM_REGION MPU_REGION_NUMBER10 +#define CPY_SDRAM_REGION_SIZE MPU_REGION_SIZE_64MB 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/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. } 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..6179197fa95c9 --- /dev/null +++ b/ports/stm/peripherals/sdram.c @@ -0,0 +1,293 @@ +// 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 +#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 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(const struct stm32_sdram_config *config); + +void sdram_init(const struct stm32_sdram_config *config) { + 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; + 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 = 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(config); + +} +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(const struct stm32_sdram_config *config) { + FMC_SDRAM_CommandTypeDef command = {0}; + /* Program the SDRAM external device */ + + 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; + HAL_SDRAM_SendCommand(&hsdram, &command, HAL_MAX_DELAY); + + HAL_Delay(config->power_up_delay); + + /* Configure a PALL (precharge all) command */ + command.CommandMode = FMC_SDRAM_CMD_PALL; + HAL_SDRAM_SendCommand(&hsdram, &command, HAL_MAX_DELAY); + + /* Configure a Auto-Refresh command */ + command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; + HAL_SDRAM_SendCommand(&hsdram, &command, HAL_MAX_DELAY); + + command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; + /* load mode */ + HAL_SDRAM_SendCommand(&hsdram, &command, HAL_MAX_DELAY); + + /* program refresh count */ + HAL_SDRAM_ProgramRefreshRate(&hsdram, config->refresh_rate); + + #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 + +} + +#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; + 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 < hsdram.Init.MemoryDataWidth; 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 // sdram_test diff --git a/ports/stm/peripherals/sdram.h b/ports/stm/peripherals/sdram.h new file mode 100644 index 0000000000000..46343b6861e43 --- /dev/null +++ b/ports/stm/peripherals/sdram.h @@ -0,0 +1,47 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 snkYmkrct +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "stm32h7xx_ll_fmc.h" +#include +#include + +#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); +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..25cb9efcde03e 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->D2CFGR & RCC_D2CFGR_D2PPRE2) >> RCC_D2CFGR_D2PPRE2_Pos; + #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->D1CFGR & RCC_D1CFGR_D1PPRE) >> RCC_D1CFGR_D1PPRE_Pos; + #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..5f29eaaf9625a 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -42,6 +42,15 @@ void NVIC_SystemReset(void) NORETURN; #if (CPY_STM32H7) || (CPY_STM32F7) +#if defined(CIRCUITPY_HW_SDRAM_SIZE) +#include "stm.h" +#include "sdram.h" +#include +#include +#include "lib/tlsf/tlsf.h" +// internal SRAM + external SDRAM +#define CIRCUITPY_RAM_DEVICE_COUNT (2) +#endif // Device memories must be accessed in order. #define DEVICE 2 @@ -146,6 +155,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 +176,62 @@ __attribute__((used, naked)) void Reset_Handler(void) { // Low power clock variables static volatile uint32_t systick_ms; +#if defined(CIRCUITPY_HW_SDRAM_SIZE) +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 +} + +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); +} + +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); + size_t sdram_memory_size = sdram_size(); + + _heap = tlsf_create_with_pool(heap_bottom, size, size + sdram_memory_size); + pools[0] = tlsf_get_pool(_heap); +} + +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 +265,9 @@ safe_mode_t port_init(void) { __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); stm32_peripherals_rtc_reset_alarms(); + #if defined(CIRCUITPY_HW_SDRAM_SIZE) + _port_heap_init(); + #endif // Turn off SysTick SysTick->CTRL = 0; 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); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy