From 6a8989f34747ace55efbf777cbca1aa234717e84 Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Tue, 30 Dec 2025 00:33:59 +0000 Subject: [PATCH] echoplayer: enable SD card using sdmmc_host Enable pullups on SDMMC CMD/DATx lines and set output speed to medium. Using HIGH and VERYHIGH speeds seems to cause data corruption, with frequent CRC failures. Change-Id: I732d19e03a2a857453755b68b6749497eafaef70 --- firmware/SOURCES | 1 + firmware/export/config/echor1.h | 3 + .../arm/stm32/echoplayer/clock-echoplayer.c | 15 ++- .../arm/stm32/echoplayer/sdmmc-echoplayer.c | 116 ++++++++++++++++++ .../arm/stm32/echoplayer/system-echoplayer.c | 6 +- 5 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 firmware/target/arm/stm32/echoplayer/sdmmc-echoplayer.c diff --git a/firmware/SOURCES b/firmware/SOURCES index d8488d5410..6c238fb1ca 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -2038,6 +2038,7 @@ target/arm/stm32/echoplayer/button-echoplayer.c target/arm/stm32/echoplayer/clock-echoplayer.c target/arm/stm32/echoplayer/lcd-echoplayer.c target/arm/stm32/echoplayer/power-echoplayer.c +target/arm/stm32/echoplayer/sdmmc-echoplayer.c target/arm/stm32/echoplayer/system-echoplayer.c #endif diff --git a/firmware/export/config/echor1.h b/firmware/export/config/echor1.h index 7467ebcc97..8b74a2cade 100644 --- a/firmware/export/config/echor1.h +++ b/firmware/export/config/echor1.h @@ -67,6 +67,9 @@ #define STORAGE_WANTS_ALIGN #define STORAGE_NEEDS_BOUNCE_BUFFER +/* One SD card slot */ +#define SDMMC_HOST_NUM_SD_CONTROLLERS 1 + /* RTC settings */ #define CONFIG_RTC RTC_STM32H743 #define HAVE_RTC_ALARM diff --git a/firmware/target/arm/stm32/echoplayer/clock-echoplayer.c b/firmware/target/arm/stm32/echoplayer/clock-echoplayer.c index d8ddb10330..fcf26ae3dc 100644 --- a/firmware/target/arm/stm32/echoplayer/clock-echoplayer.c +++ b/firmware/target/arm/stm32/echoplayer/clock-echoplayer.c @@ -27,6 +27,8 @@ #include "regs/stm32h743/rcc.h" #include "regs/stm32h743/syscfg.h" +#define PLL1Q_FREQ 48000000 + /* Flag to use VOS0 */ #define STM32H743_USE_VOS0 (CPU_FREQ > 400000000) @@ -44,6 +46,8 @@ static void init_pll(void) "HSE frequency not correct"); _Static_assert(LCD_DOTCLOCK_FREQ == 6199200, "PLL3 parameters not correct for dot clock"); + _Static_assert(PLL1Q_FREQ == 48000000, + "PLL1Q parameters not correct"); /* * Use HSE/4 input for PLL1 @@ -76,7 +80,7 @@ static void init_pll(void) reg_writef(RCC_PLL1DIVR, DIVN(80 - 1), /* 6 * 80 = 480 MHz */ DIVP(1 - 1), /* 480 / 1 = 480 MHz */ - DIVQ(8 - 1), /* 480 / 8 = 60 MHz */ + DIVQ(10 - 1), /* 480 / 10 = 48 MHz */ DIVR(1 - 1)); reg_writef(RCC_PLL3FRACR, FRACN(1468)); @@ -159,6 +163,7 @@ static void init_lse(void) static void init_periph_clock(void) { + reg_writef(RCC_D1CCIPR, SDMMCSEL_V(PLL1Q)); reg_writef(RCC_D2CCIP1R, SPI45SEL_V(HSE)); /* Enable AXI SRAM in sleep mode to allow DMA'ing out of it */ @@ -189,6 +194,11 @@ void stm_target_clock_enable(enum stm_clock clock, bool enable) reg_writef(RCC_APB3LPENR, LTDCEN(enable)); break; + case STM_CLOCK_SDMMC1_KER: + reg_writef(RCC_AHB3ENR, SDMMC1EN(enable)); + reg_writef(RCC_AHB3LPENR, SDMMC1EN(enable)); + break; + default: panicf("%s: unsupported clock %d", __func__, (int)clock); break; @@ -202,6 +212,9 @@ size_t stm_target_clock_get_frequency(enum stm_clock clock) case STM_CLOCK_SPI5_KER: return STM32_HSE_FREQ; + case STM_CLOCK_SDMMC1_KER: + return PLL1Q_FREQ; + default: panicf("%s: unsupported clock %d", __func__, (int)clock); return 0; diff --git a/firmware/target/arm/stm32/echoplayer/sdmmc-echoplayer.c b/firmware/target/arm/stm32/echoplayer/sdmmc-echoplayer.c new file mode 100644 index 0000000000..5120cca473 --- /dev/null +++ b/firmware/target/arm/stm32/echoplayer/sdmmc-echoplayer.c @@ -0,0 +1,116 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2025 by Aidan MacDonald + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "sdmmc_host.h" +#include "sdmmc-stm32h7.h" +#include "gpio-stm32h7.h" +#include "nvic-arm.h" +#include "regs/stm32h743/sdmmc.h" + +/* 300ms poll interval */ +#define SDCARD_POLL_TICKS (300 * HZ / 1000) + +static struct sdmmc_host sdmmc1; +static struct stm32h7_sdmmc_controller sdmmc1_ctl; + +static const struct sdmmc_controller_ops sdmmc_ops = { + .set_power_enabled = stm32h7_sdmmc_set_power_enabled, + .set_bus_width = stm32h7_sdmmc_set_bus_width, + .set_bus_clock = stm32h7_sdmmc_set_bus_clock, + .submit_command = stm32h7_sdmmc_submit_command, + .abort_command = stm32h7_sdmmc_abort_command, +}; + +static const struct sdmmc_host_config sdmmc_config INITDATA_ATTR = { + .type = STORAGE_SD, + .bus_voltages = SDMMC_BUS_VOLTAGE_3V2_3V3 | + SDMMC_BUS_VOLTAGE_3V3_3V4, + .bus_widths = SDMMC_BUS_WIDTH_1BIT | + SDMMC_BUS_WIDTH_4BIT, + .bus_clocks = SDMMC_BUS_CLOCK_400KHZ | + SDMMC_BUS_CLOCK_25MHZ | + SDMMC_BUS_CLOCK_50MHZ, + .is_removable = true, +}; + +/* + * simple SD insertion poller + */ +struct sdmmc_poll +{ + struct sdmmc_host *host; + bool is_inserted; + + bool last_state; + bool curr_state; +}; + +static bool is_sdcard_inserted(void) +{ + return gpio_get_level(GPIO_SDMMC_DETECT) == 0; +} + +static int poll_sdcard_inserted(struct timeout *tmo) +{ + struct sdmmc_poll *poll = (void *)tmo->data; + + poll->last_state = poll->curr_state; + poll->curr_state = is_sdcard_inserted(); + + if (!poll->curr_state && poll->is_inserted) + { + poll->is_inserted = false; + sdmmc_host_set_medium_present(poll->host, false); + } + else if (poll->curr_state && !poll->is_inserted && + poll->curr_state == poll->last_state) + { + poll->is_inserted = true; + sdmmc_host_set_medium_present(poll->host, true); + } + + return SDCARD_POLL_TICKS; +} + +static struct timeout sdcard_poll_timeout; +static struct sdmmc_poll sdcard_poll; + +void sdmmc_host_target_init(void) +{ + /* Initialize controller */ + stm32h7_sdmmc_init(&sdmmc1_ctl, ITA_SDMMC1, STM_CLOCK_SDMMC1_KER, + stm32h7_reset_sdmmc1, NULL); + nvic_enable_irq(NVIC_IRQN_SDMMC1); + + /* Initialize card detect polling */ + sdcard_poll.host = &sdmmc1; + sdcard_poll.is_inserted = is_sdcard_inserted(); + timeout_register(&sdcard_poll_timeout, poll_sdcard_inserted, + SDCARD_POLL_TICKS, (intptr_t)&sdcard_poll); + + /* Initialize SD/MMC host driver */ + sdmmc_host_init(&sdmmc1, &sdmmc_config, &sdmmc_ops, &sdmmc1_ctl); + sdmmc_host_init_medium_present(&sdmmc1, sdcard_poll.is_inserted); +} + +void sdmmc1_irq_handler(void) +{ + stm32h7_sdmmc_irq_handler(&sdmmc1_ctl); +} diff --git a/firmware/target/arm/stm32/echoplayer/system-echoplayer.c b/firmware/target/arm/stm32/echoplayer/system-echoplayer.c index 5a7fba9a47..f00545bb2b 100644 --- a/firmware/target/arm/stm32/echoplayer/system-echoplayer.c +++ b/firmware/target/arm/stm32/echoplayer/system-echoplayer.c @@ -32,7 +32,8 @@ #define F_ULPI GPIOF_FUNCTION(10, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) #define F_MCO1 GPIOF_FUNCTION(0, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) #define F_I2C1 GPIOF_FUNCTION(4, GPIO_TYPE_OPEN_DRAIN, GPIO_SPEED_LOW, GPIO_PULL_DISABLED) -#define F_SDMMC1 GPIOF_FUNCTION(12, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) +#define F_SDMMC1 GPIOF_FUNCTION(12, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_MEDIUM, GPIO_PULL_UP) +#define F_SDMMC1CK GPIOF_FUNCTION(12, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_MEDIUM, GPIO_PULL_DISABLED) #define F_SAI1 GPIOF_FUNCTION(6, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) #define F_SPI5 GPIOF_FUNCTION(5, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) #define F_LCD_AF14 GPIOF_FUNCTION(14, GPIO_TYPE_PUSH_PULL, GPIO_SPEED_VERYHIGH, GPIO_PULL_DISABLED) @@ -93,7 +94,8 @@ static const struct pingroup_setting pingroups[] = { /* I2C1 */ STM_DEFPINS(GPIO_B, 0x00c0, F_I2C1), /* SDMMC1 */ - STM_DEFPINS(GPIO_C, 0x1f00, F_SDMMC1), + STM_DEFPINS(GPIO_C, 0x1000, F_SDMMC1CK), + STM_DEFPINS(GPIO_C, 0x0f00, F_SDMMC1), STM_DEFPINS(GPIO_D, 0x0004, F_SDMMC1), /* SAI1 */ STM_DEFPINS(GPIO_E, 0x007c, F_SAI1),