diff --git a/firmware/target/arm/stm32/echoplayer/clock-echoplayer.c b/firmware/target/arm/stm32/echoplayer/clock-echoplayer.c index 277e534932..cd790f4c16 100644 --- a/firmware/target/arm/stm32/echoplayer/clock-echoplayer.c +++ b/firmware/target/arm/stm32/echoplayer/clock-echoplayer.c @@ -162,3 +162,16 @@ void stm_target_clock_enable(enum stm_clock clock, bool enable) break; } } + +size_t stm_target_clock_get_frequency(enum stm_clock clock) +{ + switch (clock) + { + case STM_CLOCK_SPI5_KER: + return STM32_HSE_FREQ; + + default: + panicf("%s: unsupported clock %d", __func__, (int)clock); + return 0; + } +} diff --git a/firmware/target/arm/stm32/echoplayer/lcd-echoplayer.c b/firmware/target/arm/stm32/echoplayer/lcd-echoplayer.c index cabeacd26c..370230ee2f 100644 --- a/firmware/target/arm/stm32/echoplayer/lcd-echoplayer.c +++ b/firmware/target/arm/stm32/echoplayer/lcd-echoplayer.c @@ -28,9 +28,13 @@ #include "regs/stm32h743/rcc.h" #include "regs/stm32h743/spi.h" +/* ILI9342C specifies 10 MHz max */ +#define LCD_SPI_FREQ 10000000 + struct stm_spi_config spi_cfg = { .instance = ITA_SPI5, .clock = STM_CLOCK_SPI5_KER, + .freq = LCD_SPI_FREQ, .mode = STM_SPIMODE_HALF_DUPLEX, .proto = STM_SPIPROTO_MOTOROLA, .frame_bits = 9, diff --git a/firmware/target/arm/stm32/spi-stm32h7.c b/firmware/target/arm/stm32/spi-stm32h7.c index 70fd7e738b..941310f90d 100644 --- a/firmware/target/arm/stm32/spi-stm32h7.c +++ b/firmware/target/arm/stm32/spi-stm32h7.c @@ -108,10 +108,23 @@ static void stm_spi_unpack(void **bufp, size_t *sizep, uint32_t data) *sizep = 0; } +static uint32_t stm_spi_calc_mbr(const struct stm_spi_config *config) +{ + size_t ker_freq = stm_clock_get_frequency(config->clock); + for (uint32_t mbr = 0; mbr <= 7; mbr++) + { + if (ker_freq / (2 << mbr) <= config->freq) + return mbr; + } + + panicf("%s: impossible frequency", __func__); +} + void stm_spi_init(struct stm_spi *spi, const struct stm_spi_config *config) { uint32_t ftlevel; + uint32_t mbr = stm_spi_calc_mbr(config); spi->regs = config->instance; spi->clock = config->clock; @@ -153,7 +166,7 @@ void stm_spi_init(struct stm_spi *spi, /* TODO: allow setting MBR here */ reg_writelf(spi->regs, SPI_CFG1, - MBR(0), + MBR(mbr), CRCEN(0), CRCSIZE(7), TXDMAEN(0), diff --git a/firmware/target/arm/stm32/spi-stm32h7.h b/firmware/target/arm/stm32/spi-stm32h7.h index 5d4d77dbbf..dbc6a2fdaa 100644 --- a/firmware/target/arm/stm32/spi-stm32h7.h +++ b/firmware/target/arm/stm32/spi-stm32h7.h @@ -50,7 +50,17 @@ struct stm_spi_config { /* Peripheral instance base address; one of ITA_SPIx */ uint32_t instance; + + /* + * SPI kernel clock and requested SPI bus frequency. + * The frequency is used to set the SPI master baud + * rate setting based on the kernel clock input, as + * such the kernel clock should not be changed after + * the SPI peripheral is initialized. + */ enum stm_clock clock; + size_t freq; + enum stm_spi_mode mode; enum stm_spi_protocol proto; stm_spi_set_cs_t set_cs;