From e38fc727afeb7826529a393e6a4f537bb3d93461 Mon Sep 17 00:00:00 2001 From: Hauke Petersen Date: Tue, 8 Nov 2016 18:13:33 +0100 Subject: [PATCH] cpu/stm32_common: added SPI div calc tool --- cpu/stm32_common/dist/spi_divtable/Makefile | 12 ++ .../dist/spi_divtable/spi_divtable.c | 105 ++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 cpu/stm32_common/dist/spi_divtable/Makefile create mode 100644 cpu/stm32_common/dist/spi_divtable/spi_divtable.c diff --git a/cpu/stm32_common/dist/spi_divtable/Makefile b/cpu/stm32_common/dist/spi_divtable/Makefile new file mode 100644 index 0000000000..e5b5461972 --- /dev/null +++ b/cpu/stm32_common/dist/spi_divtable/Makefile @@ -0,0 +1,12 @@ +NAME = spi_divtable +CC = gcc +CFLAGS = -std=c99 -Wall +SRC = $(wildcard *.c) + +.PHONY: all clean + +all: + $(CC) $(CFLAGS) -o $(NAME) $(SRC) + +clean: + rm -f $(NAME) diff --git a/cpu/stm32_common/dist/spi_divtable/spi_divtable.c b/cpu/stm32_common/dist/spi_divtable/spi_divtable.c new file mode 100644 index 0000000000..70eed10901 --- /dev/null +++ b/cpu/stm32_common/dist/spi_divtable/spi_divtable.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @brief Compute SPI clock scaler values for STM32x CPUs + * + * This helper tool calculates the needed SPI scaler values for the APBx buses. + * It outputs the values for the possible SPI clock speeds based on the clock + * speeds of the APB1 and the APB2 bus. + * + * @author Hauke Petersen + * + * @} + */ + +#include +#include +#include + + +static int targets[] = { 100000, 400000, 1000000, 5000000, 10000000 }; + +/** + * @brief Find the best fitting divisor value base on target and APB clock + * + * The SPI bus clock speed is calculated as follows: + * + * clk_bus = clk_apb / 2 ^ (x + 1) + * + * In this function we will try to find the x-value, that brings clk_bus as + * close as possible to the value given in @p target. + * + * @param[in] bus clock speed of the given APB bus + * @param[in] target targeted SPI clock speed + * + * @return the closes divisor value to be used in the clock config register + */ +static int find_best(int bus, int target) +{ + int br = -1; + int tmp = bus; + + do { + // printf("b: x: %i - tmp: %i\n", br, tmp); + ++br; + tmp /= 2; + if (tmp == target) { + return br; + } + // printf("a: x: %i - tmp: %i\n", br, tmp); + // printf(" (tmp - target):%i\n", (tmp - target)); + } while ((tmp - target > 0) && (br < 7)); + + int old = tmp * 2; + // printf("(target - tmp):%i, (old - target): %i\n", (target - tmp), (old - target)); + + if ((target - tmp) > (old - target)) { + return (br - 1); + } + return br; +} + +static int real_clk(int bus, int br) +{ + return bus / (2 << br); +} + +int main(int argc, char **argv) +{ + int tnum = sizeof(targets) / sizeof(targets[0]); + int apb[2]; + + if (argc != 3) { + printf("usage: %s (in Hz)\n", argv[0]); + return 1; + } + + apb[0] = atoi(argv[1]); /* APB1 */ + apb[1] = atoi(argv[2]); /* APB2 */ + + if ((apb[0] <= 0) || (apb[1] <= 0)) { + puts("error: invalid APB clock speed values"); + return 1; + } + + printf("static const uint8_t spi_divtable[2][%i] = {\n", tnum); + + for (int bus = 0; bus < (sizeof(apb) / sizeof(apb[0])); bus ++) { + printf(" { /* for APB%i @ %iHz */\n", (bus + 1), apb[bus]); + for (int t = 0; t < tnum; t++) { + int br = find_best(apb[bus], targets[t]); + printf(" %i%c /* -> %iHz */\n", + br, ((t < (tnum - 1)) ? ',' : ' '), real_clk(apb[bus], br)); + } + printf(" }%c\n", ((bus == 0) ? ',' : ' ')); + } + puts("};"); + + return 0; +}