diff --git a/boards/common/stm32/include/f4/cfg_clock_96_25_1.h b/boards/common/stm32/include/f4/cfg_clock_96_25_1.h new file mode 100644 index 0000000000..e518027bee --- /dev/null +++ b/boards/common/stm32/include/f4/cfg_clock_96_25_1.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2018 Freie Universität Berlin + * 2017 OTA keys S.A. + * 2018 Inria + * + * 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. + */ + +/** + * @ingroup boards_common_stm32 + * @{ + * + * @file + * @brief Configure STM32F4 clock to 96MHz using PLL + * + * @author Hauke Petersen + * @author Vincent Dupont + * @author Alexandre Abadie + */ + +#ifndef F4_CFG_CLOCK_96_25_1_H +#define F4_CFG_CLOCK_96_25_1_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Clock settings + * + * @note This is auto-generated from + * `cpu/stm32_common/dist/clk_conf/clk_conf.c` + * @{ + */ +/* give the target core clock (HCLK) frequency [in Hz], + * maximum: 100MHz */ +#define CLOCK_CORECLOCK (96000000U) +/* 0: no external high speed crystal available + * else: actual crystal frequency [in Hz] */ +#define CLOCK_HSE (25000000U) +/* 0: no external low speed crystal available, + * 1: external crystal available (always 32.768kHz) */ +#define CLOCK_LSE (1U) +/* peripheral clock setup */ +#define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 +#define CLOCK_AHB (CLOCK_CORECLOCK / 1) +#define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV2 /* max 50MHz */ +#define CLOCK_APB1 (CLOCK_CORECLOCK / 2) +#define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV1 /* max 100MHz */ +#define CLOCK_APB2 (CLOCK_CORECLOCK / 1) + +/* Main PLL factors */ +#define CLOCK_PLL_M (25) +#define CLOCK_PLL_N (384) +#define CLOCK_PLL_P (4) +#define CLOCK_PLL_Q (8) +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* F4_CFG_CLOCK_96_25_1_H */ +/** @} */ diff --git a/boards/weact-f411ce/Makefile b/boards/weact-f411ce/Makefile new file mode 100644 index 0000000000..f8fcbb53a0 --- /dev/null +++ b/boards/weact-f411ce/Makefile @@ -0,0 +1,3 @@ +MODULE = board + +include $(RIOTBASE)/Makefile.base diff --git a/boards/weact-f411ce/Makefile.dep b/boards/weact-f411ce/Makefile.dep new file mode 100644 index 0000000000..d06654049c --- /dev/null +++ b/boards/weact-f411ce/Makefile.dep @@ -0,0 +1,11 @@ +ifneq (,$(filter saul_default,$(USEMODULE))) + USEMODULE += saul_gpio +endif + +ifeq (,$(filter stdio_% slipdev_stdio,$(USEMODULE))) + USEMODULE += stdio_cdc_acm +endif + +ifneq (,$(filter mtd,$(USEMODULE))) + USEMODULE += mtd_spi_nor +endif diff --git a/boards/weact-f411ce/Makefile.features b/boards/weact-f411ce/Makefile.features new file mode 100644 index 0000000000..02ea545f69 --- /dev/null +++ b/boards/weact-f411ce/Makefile.features @@ -0,0 +1,12 @@ +CPU = stm32 +CPU_MODEL = stm32f411ceu6 + +# Put defined MCU peripherals here (in alphabetical order) +FEATURES_PROVIDED += periph_adc +FEATURES_PROVIDED += periph_i2c +FEATURES_PROVIDED += periph_pwm +FEATURES_PROVIDED += periph_rtc +FEATURES_PROVIDED += periph_spi +FEATURES_PROVIDED += periph_timer +FEATURES_PROVIDED += periph_uart +FEATURES_PROVIDED += periph_usbdev diff --git a/boards/weact-f411ce/Makefile.include b/boards/weact-f411ce/Makefile.include new file mode 100644 index 0000000000..6b9cef1eb3 --- /dev/null +++ b/boards/weact-f411ce/Makefile.include @@ -0,0 +1,10 @@ +INCLUDES += -I$(RIOTBOARD)/common/stm32/include + +# default to flashing over USB +PROGRAMMER ?= dfu-util +DFU_USB_ID ?= 0483:df11 +DFU_FLAGS ?= -a 0 -s 0x08000000:leave +ROM_OFFSET ?= 0x0 + +# Setup of programmer and serial is shared between STM32 based boards +include $(RIOTMAKE)/boards/stm32.inc.mk diff --git a/boards/weact-f411ce/board.c b/boards/weact-f411ce/board.c new file mode 100644 index 0000000000..4a6b97aa42 --- /dev/null +++ b/boards/weact-f411ce/board.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2019 Benjamin Valentin + * + * 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. + */ + +/** + * @ingroup boards_weact-f411ce + * @{ + * + * @file + * @brief Board initialization code for the WeAct-F411CE board. + * + * @author Benjamin Valentin + * + * @} + */ + +#include "board.h" +#include "cpu.h" +#include "mtd.h" +#include "mtd_spi_nor.h" +#include "periph/gpio.h" + +#ifdef MODULE_MTD +/* AT25SF041 */ +static const mtd_spi_nor_params_t _weact_nor_params = { + .opcode = &mtd_spi_nor_opcode_default, + .wait_chip_erase = 4800LU * US_PER_MS, + .wait_32k_erase = 300LU * US_PER_MS, + .wait_sector_erase = 70LU * US_PER_MS, + .wait_4k_erase = 70LU * US_PER_MS, + .wait_chip_wake_up = 1LU * US_PER_MS, + .clk = WEACT_411CE_NOR_SPI_CLK, + .flag = WEACT_411CE_NOR_FLAGS, + .spi = WEACT_411CE_NOR_SPI_DEV, + .mode = WEACT_411CE_NOR_SPI_MODE, + .cs = WEACT_411CE_NOR_SPI_CS, + .addr_width = 3, +}; + +static mtd_spi_nor_t weact_nor_dev = { + .base = { + .driver = &mtd_spi_nor_driver, + .page_size = WEACT_411CE_NOR_PAGE_SIZE, + .pages_per_sector = WEACT_411CE_NOR_PAGES_PER_SECTOR, + .sector_count = WEACT_411CE_NOR_SECTOR_COUNT, + }, + .params = &_weact_nor_params, +}; + +mtd_dev_t *mtd0 = (mtd_dev_t *)&weact_nor_dev; +#endif /* MODULE_MTD */ + +void board_init(void) +{ + cpu_init(); + + gpio_init(LED0_PIN, GPIO_OUT); + LED0_OFF; +} diff --git a/boards/weact-f411ce/doc.txt b/boards/weact-f411ce/doc.txt new file mode 100644 index 0000000000..eedf7b9002 --- /dev/null +++ b/boards/weact-f411ce/doc.txt @@ -0,0 +1,66 @@ +/** +@defgroup boards_weact-f411ce WeAct-F411CE board +@ingroup boards +@brief Support for the WeAct-F411CE Board + +## Overview + +WeAct-F411CE is a board with the same form-factor as the blue/blackpill, +but with an STM32F411CEU6 and a USB-C connector. + +It is available on sites like AliExpress for less than 4€. + +## Hardware + +![WeAct-F411CE](https://user-images.githubusercontent.com/1301112/69389644-eb5fb080-0ccc-11ea-8002-67d3db851250.png) + +### MCU +| MCU | STM32F411CE | +|:---------------- |:--------------------- | +| Family | ARM Cortex-M4F | +| Vendor | ST Microelectronics | +| RAM | 128KiB | +| Flash | 512KiB | +| Frequency | up to 100MHz | +| FPU | yes | +| Timers | 8 (2x watchdog, 1 SysTick, 6x 16-bit) | +| ADCs | 1x 12-bit | +| UARTs | 3 | +| SPIs | 5 | +| I2Cs | 3 | +| RTC | 1 | +| Vcc | 2.0V - 3.6V | +| Datasheet | [Datasheet](https://www.st.com/resource/en/datasheet/stm32f411ce.pdf) | +| Reference Manual | [Reference Manual](https://www.st.com/content/ccc/resource/technical/document/reference_manual/9b/53/39/1c/f7/01/4a/79/DM00119316.pdf/files/DM00119316.pdf/jcr:content/translations/en.DM00119316.pdf) | + +## Flashing the device +The device comes with a bootloader that allows flashing via `dfu-util`. + +There are two buttons on the board labeled `BOOT0` and `NRST`. + + - Press and hold down `NRST` to reset the CPU + - Press `BOOT0` while keeping `NRST` held down + - Release `NRST`, afterwards release `BOOT0` + +The board will now show up as `0483:df11` - `STM32 BOOTLOADER` and will accept +firmware using the DFU protocol. + +You can upload your RIOT-firmware by typing + +``` +make BOARD=weact-f411ce flash +``` + +*Note:* You need to have write permissions to the device. +On Linux you could add yourself to the `plugdev` group and store the following as `/etc/udev/rules.d/99-weact-f411ce.rules`: + +``` +SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", GROUP="plugdev", MODE="660" +``` + +## UART + +stdio is provided through USB CDC ACM so the board can be used +without any extra hardware, save for a USB-C cable. + + */ diff --git a/boards/weact-f411ce/include/board.h b/boards/weact-f411ce/include/board.h new file mode 100644 index 0000000000..d88fbc0599 --- /dev/null +++ b/boards/weact-f411ce/include/board.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2019 Benjamin Valentin + * + * 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. + */ + +/** + * @ingroup boards_weact-f411ce + * + * @brief Support for the WeAct-F411CE Board + * @{ + * + * @file + * @brief Pin definitions and board configuration options + * + * @author Benjamin Valentin + */ + +#ifndef BOARD_H +#define BOARD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mtd.h" +#include "periph_cpu.h" +#include "timex.h" + +/** + * @name Xtimer configuration + * @{ + */ +#define XTIMER_BACKOFF (8) +#define XTIMER_OVERHEAD (6) +/** @} */ + +/** + * @brief Product & Vendor ID taken from example firmware + * that the board was shipped with. + * @{ + */ +#define INTERNAL_PERIPHERAL_VID (0x0483) +#define INTERNAL_PERIPHERAL_PID (0x5740) +/** @} */ + +/** + * @name LED pin definition and handlers + * @{ + */ +#define LED0_PORT GPIOC +#define LED0_PIN GPIO_PIN(PORT_C, 13) +#define LED0_MASK (1 << 13) + +#define LED0_ON (LED0_PORT->BSRR = (LED0_MASK << 16)) +#define LED0_OFF (LED0_PORT->BSRR = (LED0_MASK << 0)) +#define LED0_TOGGLE (LED0_PORT->ODR ^= LED0_MASK) +/** @} */ + +/** + * @name User button pin definition + * @{ + */ +#define BTN0_PIN GPIO_PIN(PORT_A, 0) +#define BTN0_MODE GPIO_IN_PU +/** @} */ + +/** + * @name WeAct-F411CE NOR flash hardware configuration + * + * The pad for the NOR Flash (U3) is not populated. + * You have to solder a serial flash yourself and adjust the parameters. + * @{ + */ +#define WEACT_411CE_NOR_PAGE_SIZE (256) +#define WEACT_411CE_NOR_PAGES_PER_SECTOR (16) +#define WEACT_411CE_NOR_SECTOR_COUNT (128) +#define WEACT_411CE_NOR_FLAGS (SPI_NOR_F_SECT_4K | SPI_NOR_F_SECT_32K) +#define WEACT_411CE_NOR_SPI_DEV SPI_DEV(0) +#define WEACT_411CE_NOR_SPI_CLK SPI_CLK_10MHZ +#define WEACT_411CE_NOR_SPI_CS GPIO_PIN(PORT_A, 4) +#define WEACT_411CE_NOR_SPI_MODE SPI_MODE_0 +/** @} */ + +/** + * @name MTD configuration + * @{ + */ +extern mtd_dev_t *mtd0; +#define MTD_0 mtd0 +/** @} */ + +/** + * @brief Initialize board specific hardware, including clock, LEDs and std-IO + */ +void board_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* BOARD_H */ +/** @} */ diff --git a/boards/weact-f411ce/include/gpio_params.h b/boards/weact-f411ce/include/gpio_params.h new file mode 100644 index 0000000000..9bb2e7baf3 --- /dev/null +++ b/boards/weact-f411ce/include/gpio_params.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2019 Benjamin Valentin + * + * 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. + */ + +/** + * @ingroup boards_weact-f411ce + * @{ + * + * @file + * @brief Board specific configuration of direct mapped GPIOs + * + * @author Benjamin Valentin + */ + +#ifndef GPIO_PARAMS_H +#define GPIO_PARAMS_H + +#include "board.h" +#include "saul/periph.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief GPIO pin configuration + */ +static const saul_gpio_params_t saul_gpio_params[] = +{ + { + .name = "LED", + .pin = LED0_PIN, + .mode = GPIO_OUT, + .flags = (SAUL_GPIO_INVERTED | SAUL_GPIO_INIT_CLEAR) + }, + { + .name = "KEY", + .pin = BTN0_PIN, + .mode = BTN0_MODE, + .flags = SAUL_GPIO_INVERTED + }, +}; + +#ifdef __cplusplus +} +#endif + +#endif /* GPIO_PARAMS_H */ +/** @} */ diff --git a/boards/weact-f411ce/include/periph_conf.h b/boards/weact-f411ce/include/periph_conf.h new file mode 100644 index 0000000000..8d12b4ea45 --- /dev/null +++ b/boards/weact-f411ce/include/periph_conf.h @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2019 Benjamin Valentin + * + * 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. + */ + +/** + * @ingroup boards_weact-f411ce + * @{ + * + * @file + * @brief Peripheral MCU configuration for the WeAct-F411CE Board + * + * @author Hauke Petersen + * @author José Ignacio Alamos + * @author Alexandre Abadie + * @author Benjamin Valentin + */ + +#ifndef PERIPH_CONF_H +#define PERIPH_CONF_H + +#include "periph_cpu.h" +#include "f4/cfg_clock_96_25_1.h" +#include "cfg_i2c1_pb8_pb9.h" +#include "cfg_timer_tim5.h" +#include "cfg_usb_otg_fs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name UART configuration + * @{ + */ +static const uart_conf_t uart_config[] = { + { + .dev = USART2, + .rcc_mask = RCC_APB1ENR_USART2EN, + .rx_pin = GPIO_PIN(PORT_A, 3), + .tx_pin = GPIO_PIN(PORT_A, 2), + .rx_af = GPIO_AF7, + .tx_af = GPIO_AF7, + .bus = APB1, + .irqn = USART2_IRQn, +#ifdef MODULE_PERIPH_DMA + .dma = DMA_STREAM_UNDEF, + .dma_chan = UINT8_MAX, +#endif + }, + { + .dev = USART1, + .rcc_mask = RCC_APB2ENR_USART1EN, + .rx_pin = GPIO_PIN(PORT_A, 10), + .tx_pin = GPIO_PIN(PORT_A, 9), + .rx_af = GPIO_AF7, + .tx_af = GPIO_AF7, + .bus = APB2, + .irqn = USART1_IRQn, +#ifdef MODULE_PERIPH_DMA + .dma = DMA_STREAM_UNDEF, + .dma_chan = UINT8_MAX, +#endif + }, +}; + +/* assign ISR vector names */ +#define UART_0_ISR isr_usart2 +#define UART_1_ISR isr_usart1 + +/* deduct number of defined UART interfaces */ +#define UART_NUMOF ARRAY_SIZE(uart_config) +/** @} */ + +/** @name PWM configuration + * @{ + */ +static const pwm_conf_t pwm_config[] = { + { + .dev = TIM2, + .rcc_mask = RCC_APB1ENR_TIM2EN, + .chan = { { .pin = GPIO_PIN(PORT_A, 15), .cc_chan = 0 }, + { .pin = GPIO_PIN(PORT_B, 3), /* D3 */ .cc_chan = 1 }, + { .pin = GPIO_PIN(PORT_B, 10), /* D6 */ .cc_chan = 2 }, + { .pin = GPIO_UNDEF, .cc_chan = 0 } }, + .af = GPIO_AF1, + .bus = APB1 + }, + { + .dev = TIM3, + .rcc_mask = RCC_APB1ENR_TIM3EN, + .chan = { { .pin = GPIO_PIN(PORT_B, 4), /* D5 */ .cc_chan = 0 }, + { .pin = GPIO_PIN(PORT_C, 7), /* D9 */ .cc_chan = 1 }, + { .pin = GPIO_PIN(PORT_C, 8), .cc_chan = 2 }, + { .pin = GPIO_PIN(PORT_C, 9), .cc_chan = 3 } }, + .af = GPIO_AF2, + .bus = APB1 + }, +}; + +#define PWM_NUMOF ARRAY_SIZE(pwm_config) +/** @} */ + +/** + * @name SPI configuration + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` + * @{ + */ +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 48000000Hz */ + 7, /* -> 187500Hz */ + 6, /* -> 375000Hz */ + 5, /* -> 750000Hz */ + 2, /* -> 6000000Hz */ + 1 /* -> 12000000Hz */ + }, + { /* for APB2 @ 96000000Hz */ + 7, /* -> 375000Hz */ + 7, /* -> 375000Hz */ + 6, /* -> 750000Hz */ + 3, /* -> 6000000Hz */ + 2 /* -> 12000000Hz */ + } +}; + +static const spi_conf_t spi_config[] = { + { /* U3 - SPI flash */ + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_PIN(PORT_A, 4), + .mosi_af = GPIO_AF5, + .miso_af = GPIO_AF5, + .sclk_af = GPIO_AF5, + .cs_af = GPIO_AF5, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + }, + { + .dev = SPI2, + .mosi_pin = GPIO_PIN(PORT_B, 15), + .miso_pin = GPIO_PIN(PORT_B, 14), + .sclk_pin = GPIO_PIN(PORT_B, 13), + .cs_pin = GPIO_PIN(PORT_B, 12), + .mosi_af = GPIO_AF5, + .miso_af = GPIO_AF5, + .sclk_af = GPIO_AF5, + .cs_af = GPIO_AF5, + .rccmask = RCC_APB1ENR_SPI2EN, + .apbbus = APB1 + }, + { + .dev = SPI3, + .mosi_pin = GPIO_PIN(PORT_B, 5), + .miso_pin = GPIO_PIN(PORT_B, 4), + .sclk_pin = GPIO_PIN(PORT_B, 3), + .cs_pin = GPIO_PIN(PORT_A, 15), + .mosi_af = GPIO_AF6, + .miso_af = GPIO_AF6, + .sclk_af = GPIO_AF6, + .cs_af = GPIO_AF6, + .rccmask = RCC_APB1ENR_SPI3EN, + .apbbus = APB1 + }, +}; + +#define SPI_NUMOF ARRAY_SIZE(spi_config) +/** @} */ + +/** + * @name ADC configuration + * + * Note that we do not configure all ADC channels, + * and not in the STM32F411 order. + * Feel free to add more if needed. + * + * @{ + */ + +#define ADC_CONFIG { \ + {GPIO_PIN(PORT_A, 0), 0, 0}, \ + {GPIO_PIN(PORT_A, 1), 0, 1}, \ + {GPIO_PIN(PORT_A, 4), 0, 4}, \ + {GPIO_PIN(PORT_B, 0), 0, 8}, \ +} + +#define ADC_NUMOF (4) +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPH_CONF_H */ +/** @} */