1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-30 08:51:19 +01:00

cpu/stm32*: remove old and unused stm32 dirs

This commit is contained in:
Alexandre Abadie 2020-05-03 14:36:18 +02:00
parent facb626b02
commit 7d4b29530a
No known key found for this signature in database
GPG Key ID: 1C919A403CAE1405
208 changed files with 0 additions and 687007 deletions

View File

@ -1,5 +0,0 @@
MODULE = stm32_common
DIRS = periph
include $(RIOTBASE)/Makefile.base

View File

@ -1,11 +0,0 @@
# All stm32 families provide pm support
USEMODULE += pm_layered
# include stm32 common functions and stm32 common periph drivers
USEMODULE += stm32_common stm32_common_periph
ifneq (,$(filter periph_usbdev,$(FEATURES_USED)))
USEMODULE += xtimer
endif
include $(RIOTCPU)/cortexm_common/Makefile.dep

View File

@ -1,11 +0,0 @@
FEATURES_PROVIDED += periph_cpuid
FEATURES_PROVIDED += periph_gpio periph_gpio_irq
FEATURES_PROVIDED += puf_sram
FEATURES_PROVIDED += periph_uart_modecfg
FEATURES_PROVIDED += periph_wdt
ifneq (,$(filter $(BOARDS_WITHOUT_HWRNG),$(BOARD)))
FEATURES_PROVIDED := $(filter-out periph_hwrng,$(FEATURES_PROVIDED))
endif
-include $(RIOTCPU)/cortexm_common/Makefile.features

View File

@ -1,44 +0,0 @@
CFLAGS += -DCPU_FAM_$(call uppercase_and_underscore,$(CPU_FAM))
# For stm32 cpu's we use the stm32_common.ld linker script
LINKFLAGS += -L$(RIOTCPU)/stm32_common/ldscripts
LINKER_SCRIPT ?= stm32_common.ld
INCLUDES += -I$(RIOTCPU)/stm32_common/include
# Compute ROM_LEN and RAM_LEN
include $(RIOTCPU)/stm32_common/stm32_mem_lengths.mk
KB := 1024
ROM_LEN_K := $(shell echo $(ROM_LEN) | sed 's/K//')
ifeq (stm32wb55rg,$(CPU_MODEL))
# adjust RAM_LEN and ROM_LEN according to CPU2 RAM_LEN and ROM_LEN
RAM_LEN_K := $(shell echo $(RAM_LEN) | sed 's/K//')
CPU2_RAM_LEN_K := $(shell echo $(CPU2_RAM_LEN) | sed 's/K//')
RAM_LEN := $(shell echo $$(( ($(RAM_LEN_K) - $(CPU2_RAM_LEN_K) ) ))K)
CPU2_ROM_LEN_K := $(shell echo $(CPU2_ROM_LEN) | sed 's/K//')
FLASHSIZE := $(shell echo $$(( ($(ROM_LEN_K) - $(CPU2_ROM_LEN_K) )* $(KB) )) )
ROM_LEN := $(shell echo $$(( ($(ROM_LEN_K) - $(CPU2_ROM_LEN_K) ) ))K)
else
FLASHSIZE := $(shell echo $$(( $(ROM_LEN_K) * $(KB) )) )
endif
# Get CPU_LINE_ variable
-include $(RIOTCPU)/$(CPU)/stm32_line.mk
CPU_LINE ?= $(shell echo $(CPU_MODEL) | cut -c -9 | tr 'a-z-' 'A-Z_')xx
# Set CFLAGS
CFLAGS += -D$(CPU_LINE) -DCPU_LINE_$(CPU_LINE)
CFLAGS += -DSTM32_FLASHSIZE=$(FLASHSIZE)U
info-stm32:
@$(COLOR_ECHO) "CPU: $(CPU_MODEL)"
@$(COLOR_ECHO) "\tLine: $(CPU_LINE)"
@$(COLOR_ECHO) "\tPin count:\t$(STM32_PINCOUNT)"
@$(COLOR_ECHO) "\tROM size:\t$(ROM_LEN) ($(FLASHSIZE) Bytes)"
@$(COLOR_ECHO) "\tRAM size:\t$(RAM_LEN)"
ifneq (,$(CCMRAM_LEN))
LINKFLAGS += $(LINKFLAGPREFIX)--defsym=_ccmram_length=$(CCMRAM_LEN)
endif

View File

@ -1,290 +0,0 @@
/*
* 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.
*/
/**
* @ingroup cpu_cortexm_common
* @{
*
* @file
* @brief Shared CPU specific function for the STM32 CPU family
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include "periph_conf.h"
#include "periph_cpu_common.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/**
* @brief Timer specific additional bus clock prescaler
*
* This prescale factor is dependent on the actual APBx bus clock divider, if
* the APBx presacler is != 1, it is set to 2, if the APBx prescaler is == 1, it
* is set to 1.
*
* See reference manuals section 'reset and clock control'.
*/
static const uint8_t apbmul[] = {
#if (CLOCK_APB1 < CLOCK_CORECLOCK)
[APB1] = 2,
#else
[APB1] = 1,
#endif
#if (CLOCK_APB2 < CLOCK_CORECLOCK)
[APB2] = 2
#else
[APB2] = 1
#endif
};
uint32_t periph_apb_clk(uint8_t bus)
{
if (bus == APB1) {
return CLOCK_APB1;
}
#if defined (CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
else if (bus == APB12) {
return CLOCK_APB1;
}
#endif
else {
return CLOCK_APB2;
}
}
uint32_t periph_timer_clk(uint8_t bus)
{
return periph_apb_clk(bus) * apbmul[bus];
}
void periph_clk_en(bus_t bus, uint32_t mask)
{
switch (bus) {
case APB1:
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
RCC->APB1ENR1 |= mask;
#else
RCC->APB1ENR |= mask;
#endif
break;
case APB2:
RCC->APB2ENR |= mask;
break;
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
case APB12:
RCC->APB1ENR2 |= mask;
break;
#endif
#if defined(CPU_FAM_STM32L0)
case AHB:
RCC->AHBENR |= mask;
break;
case IOP:
RCC->IOPENR |= mask;
break;
#elif defined(CPU_FAM_STM32L1) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3)
case AHB:
RCC->AHBENR |= mask;
break;
#elif defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \
defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32F7) || \
defined(CPU_FAM_STM32WB)
case AHB1:
RCC->AHB1ENR |= mask;
break;
/* STM32F410 RCC doesn't provide AHB2 and AHB3 */
#if !defined(CPU_LINE_STM32F410Rx)
case AHB2:
RCC->AHB2ENR |= mask;
break;
case AHB3:
RCC->AHB3ENR |= mask;
break;
#endif
#endif
default:
DEBUG("unsupported bus %d\n", (int)bus);
break;
}
/* stm32xx-errata: Delay after a RCC peripheral clock enable */
__DSB();
}
void periph_clk_dis(bus_t bus, uint32_t mask)
{
switch (bus) {
case APB1:
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
RCC->APB1ENR1 &= ~(mask);
#else
RCC->APB1ENR &= ~(mask);
#endif
break;
case APB2:
RCC->APB2ENR &= ~(mask);
break;
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
case APB12:
RCC->APB1ENR2 &= ~(mask);
break;
#endif
#if defined(CPU_FAM_STM32L0)
case AHB:
RCC->AHBENR &= ~(mask);
break;
case IOP:
RCC->IOPENR &= ~(mask);
break;
#elif defined(CPU_FAM_STM32L1) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3)
case AHB:
RCC->AHBENR &= ~(mask);
break;
#elif defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \
defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32F7) || \
defined(CPU_FAM_STM32WB)
case AHB1:
RCC->AHB1ENR &= ~(mask);
break;
/* STM32F410 RCC doesn't provide AHB2 and AHB3 */
#if !defined(CPU_LINE_STM32F410Rx)
case AHB2:
RCC->AHB2ENR &= ~(mask);
break;
case AHB3:
RCC->AHB3ENR &= ~(mask);
break;
#endif
#if defined(CPU_FAM_STM32WB)
case AHB4:
RCC->AHB3ENR &= ~(mask);
break;
#endif
#endif
default:
DEBUG("unsupported bus %d\n", (int)bus);
break;
}
}
#if defined(CPU_FAM_STM32L4)
void periph_lpclk_en(bus_t bus, uint32_t mask)
{
switch (bus) {
case APB1:
RCC->APB1SMENR1 |= mask;
break;
case APB2:
RCC->APB2SMENR |= mask;
break;
case APB12:
RCC->APB1SMENR2 |= mask;
break;
case AHB1:
RCC->AHB1SMENR |= mask;
break;
case AHB2:
RCC->AHB2SMENR |= mask;
break;
case AHB3:
RCC->AHB3SMENR |= mask;
break;
default:
DEBUG("unsupported bus %d\n", (int)bus);
break;
}
}
void periph_lpclk_dis(bus_t bus, uint32_t mask)
{
switch (bus) {
case APB1:
RCC->APB1SMENR1 &= ~(mask);
break;
case APB2:
RCC->APB2SMENR &= ~(mask);
break;
case APB12:
RCC->APB1SMENR2 &= ~(mask);
break;
case AHB1:
RCC->AHB1SMENR &= ~(mask);
break;
case AHB2:
RCC->AHB2SMENR &= ~(mask);
break;
case AHB3:
RCC->AHB3SMENR &= ~(mask);
break;
default:
DEBUG("unsupported bus %d\n", (int)bus);
break;
}
}
#elif defined(CPU_FAM_STM32F2) || \
defined(CPU_FAM_STM32F4) || \
defined(CPU_FAM_STM32F7)
void periph_lpclk_en(bus_t bus, uint32_t mask)
{
switch (bus) {
case APB1:
RCC->APB1LPENR |= mask;
break;
case APB2:
RCC->APB2LPENR |= mask;
break;
case AHB1:
RCC->AHB1LPENR |= mask;
break;
/* STM32F410 RCC doesn't provide AHB2 and AHB3 */
#if !defined(CPU_LINE_STM32F410Rx)
case AHB2:
RCC->AHB2LPENR |= mask;
break;
case AHB3:
RCC->AHB3LPENR |= mask;
break;
#endif
default:
DEBUG("unsupported bus %d\n", (int)bus);
break;
}
}
void periph_lpclk_dis(bus_t bus, uint32_t mask)
{
switch (bus) {
case APB1:
RCC->APB1LPENR &= ~(mask);
break;
case APB2:
RCC->APB2LPENR &= ~(mask);
break;
case AHB1:
RCC->AHB1LPENR &= ~(mask);
break;
/* STM32F410 RCC doesn't provide AHB2 and AHB3 */
#if !defined(CPU_LINE_STM32F410Rx)
case AHB2:
RCC->AHB2LPENR &= ~(mask);
break;
case AHB3:
RCC->AHB3LPENR &= ~(mask);
break;
#endif
default:
DEBUG("unsupported bus %d\n", (int)bus);
break;
}
}
#endif

View File

@ -1,177 +0,0 @@
/*
* Copyright (C) 2013 INRIA
* 2014 Freie Universität Berlin
* 2016 TriaGnoSys GmbH
* 2018 Kaspar Schleiser <kaspar@schleiser.de>
* 2018 OTA keys S.A.
*
*
* 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 cpu_stm32_common
* @{
*
* @file
* @brief Implementation of the kernel cpu functions
*
* @author Stefan Pfeiffer <stefan.pfeiffer@fu-berlin.de>
* @author Alaeddine Weslati <alaeddine.weslati@inria.fr>
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Nick van IJzendoorn <nijzendoorn@engineering-spirit.nl>
* @author Víctor Ariño <victor.arino@zii.aero>
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Vincent Dupont <vincent@otakeys.com>
* @author Oleg Artamonov <oleg@unwds.com>
* @author Francisco Molina <francisco.molina@inria.cl>
*
* @}
*/
#include "cpu.h"
#include "stdio_base.h"
#include "stmclk.h"
#include "periph_cpu.h"
#include "periph/init.h"
#include "board.h"
#if defined (CPU_FAM_STM32L4)
#define BIT_APB_PWREN RCC_APB1ENR1_PWREN
#else
#define BIT_APB_PWREN RCC_APB1ENR_PWREN
#endif
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F3) || \
defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32F7) || \
defined(CPU_FAM_STM32L1)
#define STM32_CPU_MAX_GPIOS (12U)
#if defined(CPU_FAM_STM32L1)
#define GPIO_CLK (AHB)
#define GPIO_CLK_ENR (RCC->AHBENR)
#define GPIO_CLK_ENR_MASK (0x0000FFFF)
#elif defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3)
#define GPIO_CLK (AHB)
#define GPIO_CLK_ENR (RCC->AHBENR)
#define GPIO_CLK_ENR_MASK (0xFFFF0000)
#elif defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \
defined(CPU_FAM_STM32F7)
#define GPIO_CLK (AHB1)
#define GPIO_CLK_ENR (RCC->AHB1ENR)
#define GPIO_CLK_ENR_MASK (0x0000FFFF)
#elif defined(CPU_FAM_STM32F1)
#define GPIO_CLK (APB2)
#define GPIO_CLK_ENR (RCC->APB2ENR)
#define GPIO_CLK_ENR_MASK (0x000001FC)
#endif
#ifndef DISABLE_JTAG
#define DISABLE_JTAG 0
#endif
/**
* @brief Initialize gpio to AIN
*
* stm32f need to have all there pins initialized to AIN so the consumption
* of the input Schmitt trigger is saved when running in STOP mode.
*
* @see https://comm.eefocus.com/media/download/index/id-1013834
*/
static void _gpio_init_ain(void)
{
uint32_t ahb_gpio_clocks;
/* enable GPIO clock and save GPIO clock configuration */
ahb_gpio_clocks = GPIO_CLK_ENR & GPIO_CLK_ENR_MASK;
periph_clk_en(GPIO_CLK, GPIO_CLK_ENR_MASK);
/* switch all GPIOs to AIN mode to minimize power consumption */
for (uint8_t i = 0; i < STM32_CPU_MAX_GPIOS; i++) {
GPIO_TypeDef *port;
port = (GPIO_TypeDef *)(GPIOA_BASE + i*(GPIOB_BASE - GPIOA_BASE));
if (IS_GPIO_ALL_INSTANCE(port)) {
if (!DISABLE_JTAG) {
#if defined(CPU_FAM_STM32F1)
switch (i) {
/* preserve JTAG pins on PORTA and PORTB */
case 0:
port->CR[0] = GPIO_CRL_CNF;
port->CR[1] = GPIO_CRH_CNF & 0x000FFFFF;
break;
case 1:
port->CR[0] = GPIO_CRL_CNF & 0xFFF00FFF;
port->CR[1] = GPIO_CRH_CNF;
break;
default:
port->CR[0] = GPIO_CRL_CNF;
port->CR[1] = GPIO_CRH_CNF;
break;
}
#else /* ! defined(CPU_FAM_STM32F1) */
switch (i) {
/* preserve JTAG pins on PORTA and PORTB */
case 0:
port->MODER = 0xABFFFFFF;
break;
case 1:
port->MODER = 0xFFFFFEBF;
break;
default:
port->MODER = 0xFFFFFFFF;
break;
}
#endif /* defined(CPU_FAM_STM32F1) */
}
else {
#if defined(CPU_FAM_STM32F1)
port->CR[0] = GPIO_CRL_CNF;
port->CR[1] = GPIO_CRH_CNF;
#else
port->MODER = 0xFFFFFFFF;
#endif
}
}
}
/* restore GPIO clocks */
periph_clk_en(GPIO_CLK, ahb_gpio_clocks);
}
#endif
void cpu_init(void)
{
/* initialize the Cortex-M core */
cortexm_init();
/* enable PWR module */
#ifndef CPU_FAM_STM32WB
periph_clk_en(APB1, BIT_APB_PWREN);
#endif
/* initialize the system clock as configured in the periph_conf.h */
stmclk_init_sysclk();
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F3) || \
defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32F7) || \
defined(CPU_FAM_STM32L1)
_gpio_init_ain();
#endif
#ifdef MODULE_PERIPH_DMA
/* initialize DMA streams */
dma_init();
#endif
/* initialize stdio prior to periph_init() to allow use of DEBUG() there */
stdio_init();
#ifdef STM32F1_DISABLE_JTAG
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_JTAGDISABLE;
#endif
/* trigger static peripheral initialization */
periph_init();
}

View File

@ -1,2 +0,0 @@
clk_conf
spi_divtable

View File

@ -1,12 +0,0 @@
NAME = clk_conf
CC = gcc
CFLAGS = -std=c99 -Wall
SRC = $(wildcard *.c)
.PHONY: all clean
all:
$(CC) $(CFLAGS) -o $(NAME) $(SRC)
clean:
rm -f $(NAME)

View File

@ -1,502 +0,0 @@
/*
* Copyright (C) 2017 OTA keys S.A.
*
* 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 clock constants for STM32F[2|4|7] CPUs
*
*
* @author Vincent Dupont <vincent@otakeys.com>
*
* @}
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include "clk_conf.h"
#define ENABLE_DEBUG (0)
#if ENABLE_DEBUG
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#else
#define DEBUG(...)
#endif
/**
* @brief Check if N/P pair is valid
*
* Check if N/P (alternatively N/Q or N/R) pair is valid with given @p vco_in and
* @p pll_out
*
* @param[in] n
* @param[in] p
* @param[in] vco_in
* @param[in] pll_out
*
* @return 1 if pair is valid, 0 otherwise
*/
static int is_n_ok(const pll_cfg_t *cfg, unsigned n, unsigned p,
unsigned vco_in, unsigned pll_out)
{
if (n >= cfg->min_n && n <= cfg->max_n &&
vco_in * n >= cfg->min_vco_output && vco_in * n <= cfg->max_vco_output &&
vco_in * n / p == pll_out) {
return 1;
}
else {
return 0;
}
}
/**
* @brief Compute PLL factors
*
* @param[in] pll_in PLL input frequency
* @param[in] pll_p_out PLL P output frequency (0 if P is not needed)
* @param[in] pll_q_out PLL Q output frequency (0 if Q is not needed)
* @param[in] pll_r_out PLL R output frequency (0 if R is not needed)
* @param[in,out] m M factor, can be preset (0, if it has to be calculated)
* @param[out] n N factor
* @param[out] p P factor
* @param[out] q Q factor
* @param[out] r R factor
*
* @return -1 if no P,N pair can be computed with given @p pll_in and @p pll_p_out
* @return 1 if no Q can be computed, M, N and P are valid
* @return 2 if no R can be computed, M, M and P are valid
* @return 3 if no Q nor R can be computed, M, M and P are valid
* @return 0 if M, N, P, Q, R are valid
*/
static int compute_pll(const pll_cfg_t *cfg, unsigned pll_in,
unsigned pll_p_out, unsigned pll_q_out, unsigned pll_r_out,
unsigned *m, unsigned *n,
unsigned *p, unsigned *q, unsigned *r)
{
(void)pll_r_out;
(void)r;
int res = 0;
unsigned vco_in;
if (*m == 0) {
unsigned found_m = 0;
unsigned found_n;
unsigned found_p;
unsigned found_q;
unsigned found_r;
unsigned found_res;
*m = cfg->min_m;
while (*m <= cfg->max_m && (res = compute_pll(cfg, pll_in, pll_p_out,
pll_q_out, pll_r_out,
m, n, p, q, r)) != 0) {
if (res > 0 && !found_m) {
found_m = *m;
found_n = *n;
found_p = *p;
found_q = *q;
found_r = *r;
found_res = res;
}
*m += cfg->inc_m;
}
if (res == 0) {
return 0;
}
if (found_m) {
*m = found_m;
*n = found_n;
*p = found_p;
*q = found_q;
*r = found_r;
return found_res;
}
else {
return -1;
}
}
else {
vco_in = pll_in / *m;
DEBUG("M=%u, vco_in=%u\n", *m, vco_in);
}
if (*m < cfg->min_m || *m > cfg->max_m ||
vco_in < cfg->min_vco_input || vco_in > cfg->max_vco_input) {
DEBUG("Invalid M=%u\n", *m);
return -1;
}
if (pll_p_out) {
DEBUG("Computing P for freq=%u\n", pll_p_out);
for (*p = cfg->max_p; *p >= cfg->min_p; *p -= cfg->inc_p) {
*n = *p * pll_p_out / vco_in;
DEBUG("Trying P=%u: N=%u\n", *p, *n);
if (is_n_ok(cfg, *n, *p, vco_in, pll_p_out)) {
DEBUG("Found M=%u, N=%u, P=%u\n", *m, *n, *p);
break;
}
}
if (*p < cfg->min_p) {
*p += cfg->inc_p;
}
if (!is_n_ok(cfg, *n, *p, vco_in, pll_p_out)) {
return -1;
}
}
if (pll_q_out) {
DEBUG("Computing Q for freq=%u\n", pll_q_out);
for (*q = cfg->max_q; *q >= cfg->min_q; *q -= cfg->inc_q) {
if (!pll_p_out) {
*n = *q * pll_q_out / vco_in;
}
DEBUG("Trying Q=%u: N=%u\n", *q, *n);
if (is_n_ok(cfg, *n, *q, vco_in, pll_q_out)) {
DEBUG("Found M=%u, N=%u, Q=%u\n", *m, *n, *q);
break;
}
}
if (*q < cfg->min_q) {
*q += cfg->inc_q;
}
if (!is_n_ok(cfg, *n, *q, vco_in, pll_q_out)) {
*q = 0;
res |= 1;
}
}
/* todo, compute r */
return res;
}
static void usage(char **argv)
{
fprintf(stderr, "usage: %s <cpu_model> <coreclock> <hse_freq> <lse> [pll_i2s_src] "
"[pll_i2s_q_out] [pll_sai_q_out]\n", argv[0]);
}
#define HSI 0
#define HSE 1
int main(int argc, char **argv)
{
if (argc < 2) {
usage(argv);
return 1;
}
if (strlen(argv[1]) < 9
|| !isdigit(argv[1][6])
|| !isdigit(argv[1][7])
|| !isdigit(argv[1][8])
|| ((argv[1][5] != 'f') && (argv[1][5] != 'F')
/* && (argv[1][5] != 'l') && (argv[1][5] != 'L') */)) {
fprintf(stderr, "Invalid model : %s\n", argv[1]);
return 1;
}
int model = atoi(argv[1] + 6);
int i;
for (i = 0; i < MODEL_MAX; i++) {
if (stm32_model[i] == model) {
break;
}
}
if (i == MODEL_MAX) {
fprintf(stderr, "Unsupported CPU model %s\n", argv[1]);
return 1;
}
const clk_cfg_t *cfg = &stm32_clk_cfg[i];
/* print help for given cpu */
if (argc < 5) {
usage(argv);
fprintf(stderr, "Max values for stm32f%03d:\n", model);
fprintf(stderr, " Max coreclock: %u Hz\n"
" Max APB1: %u Hz\n"
" Max APB2: %u Hz\n",
cfg->max_coreclock, cfg->max_apb1, cfg->max_apb2);
fprintf(stderr, "Additional PLLs:\n"
" PLL I2S: %d\n"
" PLL SAI: %d\n"
" Alternate 48MHz source: ",
cfg->has_pll_i2s, cfg->has_pll_sai);
if (cfg->has_alt_48MHz & ALT_48MHZ_I2S) {
fprintf(stderr, "PLL I2S\n");
}
else if (cfg->has_alt_48MHz & ALT_48MHZ_SAI) {
fprintf(stderr, "PLL SAI\n");
}
else {
fprintf(stderr, "None\n");
}
return 0;
}
/* parse command line arguments */
unsigned coreclock = atoi(argv[2]);
unsigned pll_in = atoi(argv[3]);
int pll_src;
if (pll_in == 0) {
pll_in = cfg->hsi;
pll_src = HSI;
}
else {
pll_src = HSE;
}
unsigned is_lse = atoi(argv[4]) ? 1 : 0;
unsigned pll_i2s_input = 0;
if (argc > 5) {
pll_i2s_input = atoi(argv[5]);
}
unsigned pll_i2s_p_out = 0;
unsigned pll_i2s_q_out = 0;
if (argc > 6) {
pll_i2s_q_out = atoi(argv[6]);
}
unsigned pll_sai_p_out = 0;
unsigned pll_sai_q_out = 0;
if (argc > 7) {
pll_sai_q_out = atoi(argv[7]);
}
if (cfg->max_coreclock && coreclock > cfg->max_coreclock) {
fprintf(stderr, "Invalid coreclock (max=%u)\n", cfg->max_coreclock);
return 1;
}
fprintf(stderr, "Computing settings for stm32f%03d CPU...\n", model);
unsigned m = 0;
unsigned n = 0;
unsigned p = 0;
unsigned q = 0;
unsigned r = 0;
unsigned m_i2s = 0;
unsigned n_i2s = 0;
unsigned p_i2s = 0;
unsigned q_i2s = 0;
unsigned r_i2s = 0;
unsigned m_sai = 0;
unsigned n_sai = 0;
unsigned p_sai = 0;
unsigned q_sai = 0;
unsigned r_sai = 0;
bool use_alt_48MHz = false;
unsigned clock_48MHz = cfg->need_48MHz ? 48000000U : 0;
if ((cfg->hsi_prediv) && (pll_src == HSI)) {
m = cfg->hsi_prediv;
}
/* main PLL */
/* try to match coreclock with P output and 48MHz for Q output (USB) */
switch (compute_pll(&cfg->pll, pll_in, coreclock, clock_48MHz, 0,
&m, &n, &p, &q, &r)) {
case -1:
/* no config available */
fprintf(stderr, "Unable to compute main PLL factors\n");
return 1;
case 1:
/* Q not OK */
fprintf(stderr, "Need to use an alternate 48MHz src...");
if (cfg->has_pll_i2s && (cfg->has_alt_48MHz & ALT_48MHZ_I2S) == ALT_48MHZ_I2S) {
puts("PLL I2S");
use_alt_48MHz = true;
if (pll_i2s_q_out != 0 && pll_i2s_q_out != 48000000U) {
fprintf(stderr, "Invalid PLL I2S Q output freq: %u\n", pll_i2s_q_out);
return 1;
}
pll_i2s_q_out = 48000000U;
}
else if (cfg->has_pll_sai && (cfg->has_alt_48MHz & ALT_48MHZ_SAI)) {
fprintf(stderr, "PLL SAI...");
use_alt_48MHz = true;
if ((cfg->has_alt_48MHz & ALT_48MHZ_P) &&
(pll_sai_p_out == 0 || pll_sai_p_out == 48000000U)) {
fprintf(stderr, "P\n");
pll_sai_p_out = 48000000U;
}
else if (!(cfg->has_alt_48MHz & ALT_48MHZ_P) &&
(pll_sai_q_out == 0 || pll_sai_q_out == 48000000U)) {
fprintf(stderr, "Q\n");
pll_sai_q_out = 48000000U;
}
else {
if (cfg->has_alt_48MHz & ALT_48MHZ_P) {
fprintf(stderr, "Invalid PLL SAI P output freq: %u\n", pll_sai_p_out);
} else {
fprintf(stderr, "Invalid PLL SAI Q output freq: %u\n", pll_sai_q_out);
}
return 1;
}
}
else {
fprintf(stderr, "No other source available\n");
return 1;
}
break;
default:
break;
}
/* PLL I2S */
if (pll_i2s_p_out || pll_i2s_q_out) {
unsigned *_m;
unsigned _in;
if (cfg->has_pll_i2s_m) {
_m = &m_i2s;
}
else {
_m = &m;
}
if (cfg->has_pll_i2s_alt_input && pll_i2s_input) {
_in = pll_i2s_input;
}
else {
_in = pll_in;
}
if (compute_pll(&cfg->pll, _in, pll_i2s_p_out, pll_i2s_q_out, 0,
_m, &n_i2s, &p_i2s, &q_i2s, &r_i2s) != 0) {
fprintf(stderr, "Unable to compute 48MHz output using PLL I2S\n");
return 1;
}
}
/* PLL SAI */
if (pll_sai_p_out || pll_sai_q_out) {
if (compute_pll(&cfg->pll, pll_in, pll_sai_p_out, pll_sai_q_out, 0,
&m_sai, &n_sai, &p_sai, &q_sai, &r_sai) != 0) {
puts("Unable to compute 48MHz output using PLL I2S");
return 1;
}
if (!cfg->has_pll_sai_m && m != m_sai) {
m = m_sai;
DEBUG("Retry to compute main PLL with M=%u\n", m);
if (compute_pll(&cfg->pll, pll_in, coreclock, clock_48MHz, 0,
&m, &n, &p, &q, &r) < 0) {
fprintf(stderr, "Unable to compute 48MHz output using PLL I2S\n");
return 1;
}
}
}
/* APB prescalers */
unsigned apb1_pre;
unsigned apb2_pre;
for (apb1_pre = 1; apb1_pre <= 16; apb1_pre <<= 1) {
if (coreclock / apb1_pre <= cfg->max_apb1) {
break;
}
}
if (cfg->family != STM32F0) {
for (apb2_pre = 1; apb2_pre <= 16; apb2_pre <<= 1) {
if (coreclock / apb2_pre <= cfg->max_apb2) {
break;
}
}
}
/* Print constants */
fprintf(stderr, "==============================================================\n");
fprintf(stderr, "Please copy the following code into your board's periph_conf.h\n\n");
printf("/**\n"
" * @name Clock settings\n"
" *\n"
" * @note This is auto-generated from\n"
" * `cpu/stm32_common/dist/clk_conf/clk_conf.c`\n"
" * @{\n"
" */\n");
printf("/* give the target core clock (HCLK) frequency [in Hz],\n"
" * maximum: %uMHz */\n", cfg->max_coreclock / 1000000U);
printf("#define CLOCK_CORECLOCK (%uU)\n", coreclock);
printf("/* 0: no external high speed crystal available\n"
" * else: actual crystal frequency [in Hz] */\n"
"#define CLOCK_HSE (%uU)\n", pll_src ? pll_in : 0);
printf("/* 0: no external low speed crystal available,\n"
" * 1: external crystal available (always 32.768kHz) */\n"
"#define CLOCK_LSE (%uU)\n", is_lse);
printf("/* peripheral clock setup */\n");
printf("#define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1\n"
"#define CLOCK_AHB (CLOCK_CORECLOCK / 1)\n");
if (cfg->family == STM32F0) {
printf("#define CLOCK_APB1_DIV RCC_CFGR_PPRE_DIV%u /* max %uMHz */\n"
"#define CLOCK_APB1 (CLOCK_CORECLOCK / %u)\n",
apb1_pre, cfg->max_apb1 / 1000000U, apb1_pre);
printf("#define CLOCK_APB2 (CLOCK_APB1)\n");
}
else {
printf("#define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV%u /* max %uMHz */\n"
"#define CLOCK_APB1 (CLOCK_CORECLOCK / %u)\n",
apb1_pre, cfg->max_apb1 / 1000000U, apb1_pre);
printf("#define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV%u /* max %uMHz */\n"
"#define CLOCK_APB2 (CLOCK_CORECLOCK / %u)\n",
apb2_pre, cfg->max_apb2 / 1000000U, apb2_pre);
}
if (cfg->family == STM32F0 || cfg->family == STM32F1 || cfg->family == STM32F3) {
printf("\n/* PLL factors */\n");
printf("#define CLOCK_PLL_PREDIV (%u)\n", m);
printf("#define CLOCK_PLL_MUL (%u)\n", n);
}
else {
printf("\n/* Main PLL factors */\n");
printf("#define CLOCK_PLL_M (%u)\n", m);
printf("#define CLOCK_PLL_N (%u)\n", n);
printf("#define CLOCK_PLL_P (%u)\n", p);
printf("#define CLOCK_PLL_Q (%u)\n", q);
}
if (pll_i2s_p_out || pll_i2s_q_out) {
printf("\n/* PLL I2S configuration */\n");
printf("#define CLOCK_ENABLE_PLL_I2S (1)\n");
if (cfg->has_pll_i2s_alt_input && pll_i2s_input) {
printf("#define CLOCK_PLL_I2S_SRC (RCC_PLLI2SCFGR_PLLI2SSRC)\n");
}
else {
printf("#define CLOCK_PLL_I2S_SRC (0)\n");
}
if (cfg->has_pll_i2s_m) {
printf("#define CLOCK_PLL_I2S_M (%u)\n", m_i2s);
}
printf("#define CLOCK_PLL_I2S_N (%u)\n", n_i2s);
printf("#define CLOCK_PLL_I2S_P (%u)\n", p_i2s);
printf("#define CLOCK_PLL_I2S_Q (%u)\n", q_i2s);
}
if (pll_sai_p_out || pll_sai_q_out) {
printf("\n/* PLL SAI configuration */\n");
printf("#define CLOCK_ENABLE_PLL_SAI (1)\n");
if (cfg->has_pll_sai_m) {
printf("#define CLOCK_PLL_SAI_M (%u)\n", m_sai);
}
printf("#define CLOCK_PLL_SAI_N (%u)\n", n_sai);
printf("#define CLOCK_PLL_SAI_P (%u)\n", p_sai);
printf("#define CLOCK_PLL_SAI_Q (%u)\n", q_sai);
}
if (use_alt_48MHz) {
printf("\n/* Use alternative source for 48MHz clock */\n");
printf("#define CLOCK_USE_ALT_48MHZ (1)\n");
}
printf("/** @} */\n");
return 0;
}

View File

@ -1,602 +0,0 @@
/*
* Copyright (C) 2017 OTA keys S.A.
*
* 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 clock constants for STM32F[2|4|7] CPUs
*
*
* @author Vincent Dupont <vincent@otakeys.com>
*
* @}
*/
#ifndef CLK_CONF_H
#define CLK_CONF_H
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name STM32 families
* @ {
*/
enum fam {
STM32F0,
STM32F1,
STM32F2,
STM32F3,
STM32F4,
STM32F7,
FAM_MAX,
};
/** @} */
/**
* @name Supported models
* @{
*/
enum {
STM32F030,
STM32F070,
STM32F031,
STM32F051,
STM32F071,
STM32F091,
STM32F042,
STM32F072,
STM32F038,
STM32F048,
STM32F058,
STM32F078,
STM32F098,
STM32F100,
STM32F101,
STM32F102,
STM32F103,
STM32F205,
STM32F207,
STM32F215,
STM32F217,
STM32F301,
STM32F302,
STM32F303,
STM32F334,
STM32F373,
STM32F318,
STM32F328,
STM32F358,
STM32F378,
STM32F398,
STM32F401,
STM32F405,
STM32F407,
STM32F410,
STM32F411,
STM32F412,
STM32F413,
STM32F415,
STM32F417,
STM32F423,
STM32F427,
STM32F429,
STM32F437,
STM32F439,
STM32F446,
STM32F469,
STM32F479,
STM32F722,
STM32F732,
STM32F746,
STM32F756,
STM32F767,
STM32F769,
STM32F777,
STM32F779,
MODEL_MAX,
};
/** @} */
/**
* @brief PLL configuration parameters
*
* PLL configuration follows the model:
* ```
*
* pll_in +----+ vco_in +------------------------------+
* --------| /M |----------|\ +----+ vco_out +----+ |
* +----+ | --| xN |-------------| /P |--|-- pll_p_out
* | +----+ \ +----+ |
* | | +----+ |
* | ---| /Q |--|-- pll_q_out
* | | +----+ |
* | | +----+ |
* | ---| /R |--|-- pll_r_out
* | +----+ |
* +------------------------------+
* ```
*
* vco_in = pll_in / M;
* vco_out = vco_in * N;
* pll_p_out = vco_out / P;
* pll_q_out = vco_out / Q;
* pll_r_out = vco_out / R;
*/
typedef struct {
unsigned min_vco_input; /**< Min VCO input */
unsigned max_vco_input; /**< Max VCO input */
unsigned min_vco_output; /**< Min VCO output */
unsigned max_vco_output; /**< Max VCO output */
unsigned min_n; /**< Min N */
unsigned max_n; /**< Max N */
unsigned inc_n; /**< Increment between two values of N */
unsigned min_m; /**< Min M */
unsigned max_m; /**< Max M */
unsigned inc_m; /**< Increment between two values of M */
unsigned min_p; /**< Min P */
unsigned max_p; /**< Max P */
unsigned inc_p; /**< Increment between two values of P */
unsigned min_q; /**< Min Q */
unsigned max_q; /**< Max Q */
unsigned inc_q; /**< Increment between two values of Q */
} pll_cfg_t;
/**
* @brief Clock configuration
*/
typedef struct {
enum fam family; /**< Family */
unsigned max_coreclock; /**< Max coreclock */
unsigned max_apb1; /**< Max APB1 clock */
unsigned max_apb2; /**< Max APB2 clock */
unsigned hsi; /**< HSI frequency */
pll_cfg_t pll; /**< PLL configuration */
bool has_pll_i2s; /**< PLL I2S available */
bool has_pll_sai; /**< PLL SAI available */
bool has_pll_i2s_m; /**< PLL I2S has a M factor */
bool has_pll_sai_m; /**< PLL SAI has a M factor */
bool has_pll_i2s_alt_input; /**< PLL I2S has an external input available */
unsigned hsi_prediv; /**< Value if HSI has a fixed prediv, 0 otherwise */
int has_alt_48MHz; /**< 48MHz can be generated by an alternate source */
bool need_48MHz; /**< 48MHz is needed */
} clk_cfg_t;
/**
* @name Alternative 48MHz sources
* @{
*/
#define ALT_48MHZ_NO 0
#define ALT_48MHZ_I2S 1
#define ALT_48MHZ_SAI 2
#define ALT_48MHZ_Q 0
#define ALT_48MHZ_P 4
/** @} */
#define STM32F(x) [STM32F##x] = x
#define STM32F0(x) [STM32F0##x] = x
/** List of supported models */
static const unsigned stm32_model[] = {
STM32F0(30),
STM32F0(70),
STM32F0(31),
STM32F0(51),
STM32F0(71),
STM32F0(91),
STM32F0(42),
STM32F0(72),
STM32F0(38),
STM32F0(48),
STM32F0(58),
STM32F0(78),
STM32F0(98),
STM32F(100),
STM32F(101),
STM32F(102),
STM32F(103),
STM32F(205),
STM32F(207),
STM32F(215),
STM32F(217),
STM32F(301),
STM32F(302),
STM32F(303),
STM32F(334),
STM32F(373),
STM32F(318),
STM32F(328),
STM32F(358),
STM32F(378),
STM32F(398),
STM32F(401),
STM32F(405),
STM32F(407),
STM32F(410),
STM32F(411),
STM32F(412),
STM32F(413),
STM32F(415),
STM32F(417),
STM32F(423),
STM32F(427),
STM32F(429),
STM32F(437),
STM32F(439),
STM32F(446),
STM32F(469),
STM32F(479),
STM32F(722),
STM32F(732),
STM32F(746),
STM32F(756),
STM32F(767),
STM32F(769),
STM32F(777),
STM32F(779),
};
/** STM32F2xx / STM32F401 PLL config */
#define stm32f2_4_192_pll_cfg { \
.min_vco_input = 1000000U, \
.max_vco_input = 2000000U, \
.min_vco_output = 192000000U, \
.max_vco_output = 432000000U, \
.min_n = 50, \
.max_n = 432, \
.inc_n = 1, \
.min_m = 2, \
.max_m = 63, \
.inc_m = 1, \
.min_p = 2, \
.max_p = 8, \
.inc_p = 2, \
.min_q = 2, \
.max_q = 15, \
.inc_q = 1, \
}
/** STM32F4 (except 401) / STM32F7 PLL config */
#define stm32f4_7_pll_cfg { \
.min_vco_input = 1000000U, \
.max_vco_input = 2000000U, \
.min_vco_output = 192000000U, \
.max_vco_output = 432000000U, \
.min_n = 50, \
.max_n = 432, \
.inc_n = 1, \
.min_m = 2, \
.max_m = 63, \
.inc_m = 1, \
.min_p = 2, \
.max_p = 8, \
.inc_p = 2, \
.min_q = 2, \
.max_q = 15, \
.inc_q = 1, \
}
/**
* @brief Clock config for supported cpu
*/
static const clk_cfg_t stm32_clk_cfg[] = {
[STM32F030 ... STM32F098] = {
.family = STM32F0,
.max_coreclock = 48000000U,
.max_apb1 = 48000000U,
.max_apb2 = 0,
.hsi = 8000000U,
.pll = {
.min_vco_input = 1000000U,
.max_vco_input = 24000000U,
.min_vco_output = 16000000U,
.max_vco_output = 48000000U,
.min_m = 1,
.max_m = 16,
.inc_m = 1,
.min_n = 2,
.max_n = 16,
.inc_n = 1,
.min_p = 1,
.max_p = 1,
.inc_p = 1,
},
.has_pll_i2s = false,
.has_pll_sai = false,
.has_pll_i2s_alt_input = false,
.has_alt_48MHz = 0,
.hsi_prediv = 2,
.need_48MHz = false,
},
[STM32F100] = {
.family = STM32F1,
.max_coreclock = 24000000U,
.max_apb1 = 24000000U,
.max_apb2 = 24000000U,
.hsi = 8000000U,
.pll = {
.min_vco_input = 1000000U,
.max_vco_input = 24000000U,
.min_vco_output = 16000000U,
.max_vco_output = 24000000U,
.min_m = 1,
.max_m = 16,
.inc_m = 1,
.min_n = 2,
.max_n = 16,
.inc_n = 1,
.min_p = 1,
.max_p = 1,
.inc_p = 1,
},
.has_pll_i2s = false,
.has_pll_sai = false,
.has_pll_i2s_alt_input = false,
.has_alt_48MHz = 0,
.hsi_prediv = 2,
.need_48MHz = false,
},
[STM32F101 ... STM32F103] = {
.family = STM32F1,
.max_coreclock = 72000000U,
.max_apb1 = 36000000U,
.max_apb2 = 72000000U,
.hsi = 8000000U,
.pll = {
.min_vco_input = 1000000U,
.max_vco_input = 25000000U,
.min_vco_output = 1000000U,
.max_vco_output = 72000000U,
.min_m = 1,
.max_m = 16,
.inc_m = 1,
.min_n = 2,
.max_n = 16,
.inc_n = 1,
.min_p = 1,
.max_p = 1,
.inc_p = 1,
},
.has_pll_i2s = false,
.has_pll_sai = false,
.has_pll_i2s_alt_input = false,
.has_alt_48MHz = 0,
.hsi_prediv = 2,
.need_48MHz = false,
},
[STM32F205 ... STM32F217] = {
.family = STM32F2,
.max_coreclock = 120000000U,
.max_apb1 = 30000000U,
.max_apb2 = 60000000U,
.hsi = 16000000U,
.pll = stm32f2_4_192_pll_cfg,
.has_pll_i2s = true,
.has_pll_sai = false,
.has_pll_i2s_alt_input = false,
.has_alt_48MHz = 0,
.need_48MHz = true,
},
[STM32F301 ... STM32F398] = {
.family = STM32F3,
.max_coreclock = 72000000U,
.max_apb1 = 36000000U,
.max_apb2 = 72000000U,
.hsi = 8000000U,
.pll = {
.min_vco_input = 1000000U,
.max_vco_input = 25000000U,
.min_vco_output = 1000000U,
.max_vco_output = 72000000U,
.min_m = 1,
.max_m = 16,
.inc_m = 1,
.min_n = 2,
.max_n = 16,
.inc_n = 1,
.min_p = 1,
.max_p = 1,
.inc_p = 1,
},
.has_pll_i2s = false,
.has_pll_sai = false,
.has_pll_i2s_alt_input = false,
.has_alt_48MHz = 0,
.hsi_prediv = 2,
.need_48MHz = false,
},
[STM32F401] = {
.family = STM32F4,
.max_coreclock = 84000000U,
.max_apb1 = 42000000U,
.max_apb2 = 84000000U,
.hsi = 16000000U,
.pll = stm32f2_4_192_pll_cfg,
.has_pll_i2s = true,
.has_pll_sai = false,
.has_pll_i2s_m = false,
.has_pll_i2s_alt_input = false,
.has_alt_48MHz = 0,
.need_48MHz = true,
},
[STM32F405 ... STM32F407] = {
.family = STM32F4,
.max_coreclock = 168000000U,
.max_apb1 = 42000000U,
.max_apb2 = 84000000U,
.hsi = 16000000U,
.pll = stm32f4_7_pll_cfg,
.has_pll_i2s = true,
.has_pll_sai = false,
.has_pll_i2s_m = false,
.has_pll_i2s_alt_input = false,
.has_alt_48MHz = 0,
.need_48MHz = true,
},
[STM32F410] = {
.family = STM32F4,
.max_coreclock = 100000000U,
.max_apb1 = 50000000U,
.max_apb2 = 100000000U,
.hsi = 16000000U,
.pll = stm32f4_7_pll_cfg,
.has_pll_i2s = false,
.has_pll_sai = false,
.has_pll_i2s_m = false,
.has_pll_i2s_alt_input = false,
.has_alt_48MHz = 0,
.need_48MHz = true,
},
[STM32F411] = {
.family = STM32F4,
.max_coreclock = 100000000U,
.max_apb1 = 50000000U,
.max_apb2 = 100000000U,
.hsi = 16000000U,
.pll = stm32f4_7_pll_cfg,
.has_pll_i2s = true,
.has_pll_sai = false,
.has_pll_i2s_m = true,
.has_pll_i2s_alt_input = false,
.has_alt_48MHz = 0,
.need_48MHz = true,
},
[STM32F412 ... STM32F413] = {
.family = STM32F4,
.max_coreclock = 100000000U,
.max_apb1 = 50000000U,
.max_apb2 = 100000000U,
.hsi = 16000000U,
.pll = stm32f4_7_pll_cfg,
.has_pll_i2s = true,
.has_pll_sai = true,
.has_pll_i2s_m = true,
.has_pll_sai_m = false,
.has_pll_i2s_alt_input = true,
.has_alt_48MHz = ALT_48MHZ_I2S,
.need_48MHz = true,
},
[STM32F415 ... STM32F417] = {
.family = STM32F4,
.max_coreclock = 168000000U,
.max_apb1 = 42000000U,
.max_apb2 = 84000000U,
.hsi = 16000000U,
.pll = stm32f4_7_pll_cfg,
.has_pll_i2s = true,
.has_pll_sai = false,
.has_pll_i2s_m = false,
.has_pll_i2s_alt_input = false,
.has_alt_48MHz = 0,
.need_48MHz = true,
},
[STM32F423] = {
.family = STM32F4,
.max_coreclock = 100000000U,
.max_apb1 = 50000000U,
.max_apb2 = 100000000U,
.hsi = 16000000U,
.pll = stm32f4_7_pll_cfg,
.has_pll_i2s = true,
.has_pll_sai = true,
.has_pll_i2s_m = true,
.has_pll_sai_m = false,
.has_pll_i2s_alt_input = true,
.has_alt_48MHz = ALT_48MHZ_I2S,
.need_48MHz = true,
},
[STM32F427 ... STM32F439] = {
.family = STM32F4,
.max_coreclock = 180000000U,
.max_apb1 = 45000000U,
.max_apb2 = 90000000U,
.hsi = 16000000U,
.pll = stm32f4_7_pll_cfg,
.has_pll_i2s = true,
.has_pll_sai = true,
.has_pll_i2s_m = false,
.has_pll_sai_m = false,
.has_pll_i2s_alt_input = false,
.has_alt_48MHz = 0,
.need_48MHz = true,
},
[STM32F446] = {
.family = STM32F4,
.max_coreclock = 180000000U,
.max_apb1 = 45000000U,
.max_apb2 = 90000000U,
.hsi = 16000000U,
.pll = stm32f4_7_pll_cfg,
.has_pll_i2s = true,
.has_pll_sai = true,
.has_pll_i2s_m = true,
.has_pll_sai_m = true,
.has_pll_i2s_alt_input = false,
.has_alt_48MHz = ALT_48MHZ_SAI | ALT_48MHZ_P,
.need_48MHz = true,
},
[STM32F469 ... STM32F479] = {
.family = STM32F4,
.max_coreclock = 180000000U,
.max_apb1 = 45000000U,
.max_apb2 = 90000000U,
.hsi = 16000000U,
.pll = stm32f4_7_pll_cfg,
.has_pll_i2s = true,
.has_pll_sai = true,
.has_pll_i2s_m = false,
.has_pll_sai_m = false,
.has_pll_i2s_alt_input = false,
.has_alt_48MHz = ALT_48MHZ_SAI | ALT_48MHZ_P,
.need_48MHz = true,
},
[STM32F722 ... STM32F779] = {
.family = STM32F7,
.max_coreclock = 216000000U,
.max_apb1 = 54000000U,
.max_apb2 = 108000000U,
.hsi = 16000000U,
.pll = stm32f4_7_pll_cfg,
.has_pll_i2s = true,
.has_pll_sai = true,
.has_pll_i2s_m = false,
.has_pll_sai_m = false,
.has_pll_i2s_alt_input = false,
.has_alt_48MHz = ALT_48MHZ_SAI | ALT_48MHZ_P,
.need_48MHz = true,
},
};
#ifdef __cplusplus
}
#endif
#endif /* CLK_CONF_H */

View File

@ -1,12 +0,0 @@
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)

View File

@ -1,105 +0,0 @@
/*
* 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 <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
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 = ARRAY_SIZE(targets);
int apb[2];
if (argc != 3) {
printf("usage: %s <APB1 clk> <APB2 clk> (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 < ARRAY_SIZE(apb); 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(" }%s\n", ((bus == 0) ? "," : ""));
}
puts("};");
return 0;
}

View File

@ -1,55 +0,0 @@
/**
* @defgroup cpu_stm32_common STM32 common
* @ingroup cpu
* @brief STM32 common code and definitions
*
* This module contains all common code and definition to all STM32 cpu
* families supported by RIOT: @ref cpu_stm32f0, @ref cpu_stm32l0,
* @ref cpu_stm32f1, @ref cpu_stm32f2, @ref cpu_stm32f3, @ref cpu_stm32f4,
* @ref cpu_stm32l4, @ref cpu_stm32f7.
*
* STM32Fx Clock configuration
* =================================
*
* stm32fx cpus share clock configuration code and macro.
* It can be configured as described here.
*
* The following macro must be defined in the board's periph_conf.h:
* - CLOCK_HSE: 0 if HSI must be used as PLL source, frequency in Hz otherwise,
* - CLOCK_LSE: 0 if LSI must be used as low speed clock, 1 otherwise
* (the LSE is a 32.768kHz crytal)
* - CLOCK_CORECLOCK: desired main clock frequency
* - CLOCK_AHB_DIV, CLOCK_AHB: AHB prescaler in register value and AHB frequecny in Hz
* - CLOCK_APB1_DIV, CLOCK_APB1: APB1 prescaler in register value and APB1 frequecny in Hz
* - CLOCK_APB2_DIV, CLOCK_APB2: APB2 prescaler in register value and APB2 frequecny in Hz
* (CLOCK_APB2_DIV is not needed for stm32f0)
*
* The following macro must be defined for stm32f[2|4|7]:
* - CLOCK_PLL_M, CLOCK_PLL_N, CLOCK_PLL_P, CLOCK_PLL_Q, (CLOCK_PLL_R, optional):
* Main PLL factors
*
* The following macro must be defined for stm32f[0|1|3]:
* - PLL_MUL, PLL_PREDIV: PLL factors. These values are used as is. A PREDIV of 2
* can be assumed when HSI is selected as PLL input. Some model support any value
* as PREDIV even with HSI though. The `clk_conf` tool will assume PREDIV must be
* to with HSI and will set it accordingly.
*
* The following macro are optional and can be defined depending on board config
* and application needs:
* - CLOCK_ENABLE_PLL_I2S: if a second PLL (PLL I2S) is available on the cpu, it
* can be activated with this macro, then CLOCK_PLL_I2S_M, CLOCK_PLL_I2S_N,
* CLOCK_PLL_I2S_P and CLOCK_PLL_I2S_Q need to be defined, CLOCK_PLL_I2S_R is optional.
* - CLOCK_ENABLE_PLL_SAI: if a second PLL (PLL SAI) is available on the cpu, it
* can be activated with this macro, then CLOCK_PLL_SAI_M, CLOCK_PLL_SAI_N,
* CLOCK_PLL_SAI_P and CLOCK_PLL_SAI_Q need to be defined, CLOCK_PLL_SAI_R is optional.
* - CLOCK_USE_ALT_48MHZ: if the 48MHz clock should be generated by the alternate
* source (PLL I2S or PLL SAI, depending on cpu)
*
* All the previous constants can be generated using the tool in
* `cpu/stm32_common/dist/clk_conf`.
*
* Clock outputs can also be setup with macro:
* - CLOCK_MCOx_SRC, CLOCK_MCOx_PRE, with x=1,2: MCO1 and MCO2 output configuration
* macros. CLOCK_MCOx_SRC defines the MCOx source, as a register value (see vendor header),
* CLOCK_MCOx_PRE defines the MCOx prescaler, as a register value.
*/

View File

@ -1,146 +0,0 @@
/*
* Copyright (C) 2016 OTA keys S.A.
*
* 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 candev_stm32
* @{
*
* @file
* @brief STM32 CAN controller driver (bxCAN) default parameters
*
* @author Vincent Dupont <vincent@otakeys.com>
* @}
*/
#ifndef CAN_PARAMS_H
#define CAN_PARAMS_H
#include "can/device.h"
#include "periph/can.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Default STM32 CAN devices config */
static const can_conf_t candev_conf[] = {
{
#if defined(CPU_FAM_STM32F0)
.can = CAN,
.rcc_mask = RCC_APB1ENR_CANEN,
.rx_pin = GPIO_PIN(PORT_A, 11),
.tx_pin = GPIO_PIN(PORT_A, 12),
.af = GPIO_AF4,
.irqn = CEC_CAN_IRQn,
#else
.can = CAN1,
#if defined(CPU_FAM_STM32L4)
.rcc_mask = RCC_APB1ENR1_CAN1EN,
#else
.rcc_mask = RCC_APB1ENR_CAN1EN,
.can_master = CAN1,
.master_rcc_mask = RCC_APB1ENR_CAN1EN,
.first_filter = 0,
.nb_filters = 14,
#endif
#if defined(CPU_FAM_STM32F1)
.rx_pin = GPIO_PIN(PORT_A, 11),
.tx_pin = GPIO_PIN(PORT_A, 12),
#elif defined(CPU_FAM_STM32L4)
.rx_pin = GPIO_PIN(PORT_B, 8),
.tx_pin = GPIO_PIN(PORT_B, 9),
.af = GPIO_AF9,
#else
.rx_pin = GPIO_PIN(PORT_D, 0),
.tx_pin = GPIO_PIN(PORT_D, 1),
.af = GPIO_AF9,
#endif
.tx_irqn = CAN1_TX_IRQn,
.rx0_irqn = CAN1_RX0_IRQn,
.rx1_irqn = CAN1_RX1_IRQn,
.sce_irqn = CAN1_SCE_IRQn,
#endif
.ttcm = 0,
.abom = 1,
.awum = 1,
.nart = 0,
.rflm = 0,
.txfp = 0,
},
#if (CANDEV_STM32_CHAN_NUMOF >= 2) && (CAN_DLL_NUMOF >= 2)
{
.can = CAN2,
.rcc_mask = RCC_APB1ENR_CAN2EN,
.can_master = CAN1,
.master_rcc_mask = RCC_APB1ENR_CAN1EN,
.first_filter = 14,
.nb_filters = 14,
.rx_pin = GPIO_PIN(PORT_B, 5),
.tx_pin = GPIO_PIN(PORT_B, 6),
#ifndef CPU_FAM_STM32F1
.af = GPIO_AF9,
#endif
.tx_irqn = CAN2_TX_IRQn,
.rx0_irqn = CAN2_RX0_IRQn,
.rx1_irqn = CAN2_RX1_IRQn,
.sce_irqn = CAN2_SCE_IRQn,
.ttcm = 0,
.abom = 1,
.awum = 1,
.nart = 0,
.rflm = 0,
.txfp = 0,
},
#endif
#if (CANDEV_STM32_CHAN_NUMOF >= 3) && (CAN_DLL_NUMOF >= 3)
{
.can = CAN3,
.rcc_mask = RCC_APB1ENR_CAN3EN,
.can_master = CAN3,
.master_rcc_mask = RCC_APB1ENR_CAN3EN,
.first_filter = 0,
.nb_filters = 14,
.rx_pin = GPIO_PIN(PORT_B, 3),
.tx_pin = GPIO_PIN(PORT_B, 4),
.af = GPIO_AF11,
.tx_irqn = CAN3_TX_IRQn,
.rx0_irqn = CAN3_RX0_IRQn,
.rx1_irqn = CAN3_RX1_IRQn,
.sce_irqn = CAN3_SCE_IRQn,
.ttcm = 0,
.abom = 1,
.awum = 1,
.nart = 0,
.rflm = 0,
.txfp = 0,
},
#endif
};
/** Default STM32 CAN devices parameters */
static const candev_params_t candev_params[] = {
{
.name = "can_stm32_0",
},
#if (CANDEV_STM32_CHAN_NUMOF >= 2) && (CAN_DLL_NUMOF >= 2)
{
.name = "can_stm32_1",
},
#endif
#if (CANDEV_STM32_CHAN_NUMOF >= 3) && (CAN_DLL_NUMOF >= 3)
{
.name = "can_stm32_2",
},
#endif
};
#ifdef __cplusplus
}
#endif
#endif /* CAN_PARAMS_H */

View File

@ -1,204 +0,0 @@
/*
* Copyright (C) 2016 OTA keys S.A.
*
* 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 cpu_stm32_common
* @ingroup drivers_can
* @defgroup candev_stm32 STM32 CAN controller
* @brief STM32 CAN controller driver (bxCAN)
*
* The STM32Fx microcontroller can have an integrated CAN controller (bxCAN)
*
* This driver has been tested with a STM32F0,STM32F2 and STM32F4 MCU
* but should work on others.
*
* The default bitrate is set to 500 kbps and the default sample point is set to
* 87.5%.
* @{
*
* @file
* @brief bxCAN specific definitions
*
* @author Vincent Dupont <vincent@otakeys.com>
* @}
*/
#ifndef CANDEV_STM32_H
#define CANDEV_STM32_H
#ifdef __cplusplus
extern "C" {
#endif
#include "can/candev.h"
#if defined(CPU_LINE_STM32F413xx) || defined(CPU_LINE_STM32F423xx)
#define CANDEV_STM32_CHAN_NUMOF 3
#elif defined(CPU_FAM_STM32F1) || defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4)
#define CANDEV_STM32_CHAN_NUMOF 2
#elif defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3) || \
defined(CPU_FAM_STM32L4) || DOXYGEN
/** Number of channels in the device (up to 3) */
#define CANDEV_STM32_CHAN_NUMOF 1
#else
#error "CAN STM32: CPU not supported"
#endif
/**
* @name ISR functions
* @{
*/
#if defined(CPU_FAM_STM32F1)
#define ISR_CAN1_TX isr_usb_hp_can1_tx
#define ISR_CAN1_RX0 isr_usb_lp_can1_rx0
#define ISR_CAN1_RX1 isr_can1_rx1
#define ISR_CAN1_SCE isr_can1_sce
#else
#define ISR_CAN1_TX isr_can1_tx
#define ISR_CAN1_RX0 isr_can1_rx0
#define ISR_CAN1_RX1 isr_can1_rx1
#define ISR_CAN1_SCE isr_can1_sce
#define ISR_CAN2_TX isr_can2_tx
#define ISR_CAN2_RX0 isr_can2_rx0
#define ISR_CAN2_RX1 isr_can2_rx1
#define ISR_CAN2_SCE isr_can2_sce
#define ISR_CAN3_TX isr_can3_tx
#define ISR_CAN3_RX0 isr_can3_rx0
#define ISR_CAN3_RX1 isr_can3_rx1
#define ISR_CAN3_SCE isr_can3_sce
#endif
/** @} */
#if CANDEV_STM32_CHAN_NUMOF > 1 || DOXYGEN
/** The maximum number of filters: 28 for dual channel, 14 for single channel */
#define CAN_STM32_NB_FILTER 28
#else
#define CAN_STM32_NB_FILTER 14
#endif
#ifndef CANDEV_STM32_DEFAULT_BITRATE
/** Default bitrate */
#define CANDEV_STM32_DEFAULT_BITRATE 500000U
#endif
#ifndef CANDEV_STM32_DEFAULT_SPT
/** Default sampling-point */
#define CANDEV_STM32_DEFAULT_SPT 875
#endif
/** bxCAN device configuration */
typedef struct {
CAN_TypeDef *can; /**< CAN device */
uint32_t rcc_mask; /**< RCC mask to enable clock */
gpio_t rx_pin; /**< RX pin */
gpio_t tx_pin; /**< TX pin */
#ifndef CPU_FAM_STM32F1
gpio_af_t af; /**< Alternate pin function to use */
#endif
#if CANDEV_STM32_CHAN_NUMOF > 1 || defined(DOXYGEN)
CAN_TypeDef *can_master; /**< Master CAN device */
uint32_t master_rcc_mask; /**< Master device RCC mask */
/** First filter in the bank. For a master channel it must be 0.
* For a slave channel, it is used without checking with the master channel,
* beware bot to overwrite the master config. */
uint8_t first_filter;
/** Number of filters to use. Must be less or equal
* to CAN_STM32_NB_FILTER - first_filter */
uint8_t nb_filters;
#endif
#if defined(CPU_FAM_STM32F0)
uint8_t irqn; /**< CAN common IRQ channel */
#else
uint8_t tx_irqn; /**< TX IRQ channel */
uint8_t rx0_irqn; /**< RX0 IRQ channel */
uint8_t rx1_irqn; /**< RX1 IRQ channel */
uint8_t sce_irqn; /**< SCE IRQ channel */
#endif
uint8_t ttcm : 1; /**< Time triggered communication mode */
uint8_t abom : 1; /**< Automatic bus-off management */
uint8_t awum : 1; /**< Automatic wakeup mode */
uint8_t nart : 1; /**< No automatic retransmission */
uint8_t rflm : 1; /**< Receive FIFO locked mode */
uint8_t txfp : 1; /**< Transmit FIFO priority */
uint8_t lbkm : 1; /**< Loopback mode */
uint8_t silm : 1; /**< Silent mode */
} can_conf_t;
/** can_conf_t is re-defined */
#define HAVE_CAN_CONF_T
/** The number of transmit mailboxes */
#define CAN_STM32_TX_MAILBOXES 3
/** The number of receive FIFO */
#define CAN_STM32_RX_MAILBOXES 2
#ifndef CAN_STM32_RX_MAIL_FIFO
/** This is the maximum number of frame the driver can receive simultaneously */
#define CAN_STM32_RX_MAIL_FIFO 12
#endif
/** bxCAN candev descriptor */
typedef struct can can_t;
/** can_t is re-defined */
#define HAVE_CAN_T
/** This structure holds anything related to the receive part */
typedef struct candev_stm32_rx_fifo {
struct can_frame frame[CAN_STM32_RX_MAIL_FIFO]; /**< Receive FIFO */
int write_idx; /**< Write index in the receive FIFO */
int read_idx; /**< Read index in the receive FIFO*/
int is_full; /**< Flag set when the FIFO is full */
} candev_stm32_rx_fifo_t;
/** Internal interrupt flags */
typedef struct candev_stm32_isr {
int isr_tx : 3; /**< Tx mailboxes interrupt */
int isr_rx : 2; /**< Rx FIFO interrupt */
int isr_wkup : 1; /**< Wake up interrupt */
} candev_stm32_isr_t;
/** STM32 CAN device descriptor */
struct can {
candev_t candev; /**< Common candev struct */
const can_conf_t *conf; /**< Configuration */
gpio_t rx_pin; /**< RX pin */
gpio_t tx_pin; /**< TX pin */
gpio_af_t af; /**< Alternate pin function to use */
/** Tx mailboxes */
const struct can_frame *tx_mailbox[CAN_STM32_TX_MAILBOXES];
candev_stm32_rx_fifo_t rx_fifo; /**< Rx FIFOs */
candev_stm32_isr_t isr_flags; /**< ISR flags */
};
#ifndef CPU_FAM_STM32F1
/**
* @brief Set the pins of an stm32 CAN device
*
* @param[in,out] dev the device to set pins
* @param[in] tx_pin tx pin
* @param[in] rx_pin rx pin
* @param[in] af alternate function
*/
void candev_stm32_set_pins(can_t *dev, gpio_t tx_pin, gpio_t rx_pin,
gpio_af_t af);
#else
/**
* @brief Set the pins of an stm32 CAN device
*
* @param[in,out] dev the device to set pins
* @param[in] tx_pin tx pin
* @param[in] rx_pin rx pin
*/
void candev_stm32_set_pins(can_t *dev, gpio_t tx_pin, gpio_t rx_pin);
#endif
#ifdef __cplusplus
}
#endif
#endif /* CANDEV_STM32_H */

View File

@ -1,119 +0,0 @@
/*
* Copyright (C) 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 cpu_stm32_common
* @{
*
* @file
* @brief Shared CPU specific configuration for STM32 family
*
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
*/
#ifndef CPU_CONF_STM32_COMMON_H
#define CPU_CONF_STM32_COMMON_H
#include "periph_cpu.h"
#include "periph/i2c.h"
#ifdef __cplusplus
extern "C" {
#endif
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3) || \
defined(CPU_FAM_STM32F7) || defined(CPU_FAM_STM32L0) || \
defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32L4) || \
defined(CPU_FAM_STM32WB)
/**
* @brief Timing register settings
*
* @ref i2c_timing_param_t
*/
static const i2c_timing_param_t timing_params[] = {
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F7) || \
defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
[ I2C_SPEED_NORMAL ] = {
.presc = 0xB,
.scll = 0x13, /* t_SCLL = 5.0us */
.sclh = 0xF, /* t_SCLH = 4.0us */
.sdadel = 0x2, /* t_SDADEL = 500ns */
.scldel = 0x4, /* t_SCLDEL = 1250ns */
},
[ I2C_SPEED_FAST ] = {
.presc = 5,
.scll = 0x9, /* t_SCLL = 1250ns */
.sclh = 0x3, /* t_SCLH = 500ns */
.sdadel = 0x3, /* t_SDADEL = 375ns */
.scldel = 0x3, /* t_SCLDEL = 500ns */
},
[ I2C_SPEED_FAST_PLUS ] = {
.presc = 5,
.scll = 0x3, /* t_SCLL = 500ns */
.sclh = 0x1, /* t_SCLH = 250ns */
.sdadel = 0x0, /* t_SDADEL = 0ns */
.scldel = 0x1, /* t_SCLDEL = 250ns */
}
#elif defined(CPU_FAM_STM32F3)
[ I2C_SPEED_NORMAL ] = {
.presc = 1,
.scll = 0x13, /* t_SCLL = 5.0us */
.sclh = 0xF, /* t_SCLH = 4.0us */
.sdadel = 0x2, /* t_SDADEL = 500ns */
.scldel = 0x4, /* t_SCLDEL = 1250ns */
},
[ I2C_SPEED_FAST ] = {
.presc = 0,
.scll = 0x9, /* t_SCLL = 1250ns */
.sclh = 0x3, /* t_SCLH = 500ns */
.sdadel = 0x1, /* t_SDADEL = 125ns */
.scldel = 0x3, /* t_SCLDEL = 500ns */
},
[ I2C_SPEED_FAST_PLUS ] = {
.presc = 0,
.scll = 0x6, /* t_SCLL = 875ns */
.sclh = 0x3, /* t_SCLH = 500ns */
.sdadel = 0x0, /* t_SDADEL = 0ns */
.scldel = 0x1, /* t_SCLDEL = 250ns */
}
#elif defined(CPU_FAM_STM32L0)
[ I2C_SPEED_NORMAL ] = {
.presc = 1,
.scll = 0x56, /* t_SCLL = 5.0us */
.sclh = 0x3E, /* t_SCLH = 4.0us */
.sdadel = 0x1, /* t_SDADEL = 500ns */
.scldel = 0xA, /* t_SCLDEL = 1250ns */
},
[ I2C_SPEED_FAST ] = {
.presc = 0,
.scll = 0x2E, /* t_SCLL = 1250ns */
.sclh = 0x11, /* t_SCLH = 500ns */
.sdadel = 0x1, /* t_SDADEL = 125ns */
.scldel = 0xB, /* t_SCLDEL = 500ns */
},
[ I2C_SPEED_FAST_PLUS ] = {
.presc = 0,
.scll = 0x6, /* t_SCLL = 875ns */
.sclh = 0x3, /* t_SCLH = 500ns */
.sdadel = 0x0, /* t_SDADEL = 0ns */
.scldel = 0x1, /* t_SCLDEL = 250ns */
}
#endif
};
#endif /* CPU_FAM_STM32F0 || CPU_FAM_STM32F3 || CPU_FAM_STM32F7 ||
CPU_FAM_STM32L0 || CPU_FAM_STM32L4 || CPU_FAM_STM32WB */
#ifdef __cplusplus
}
#endif
#endif /* CPU_CONF_STM32_COMMON_H */
/** @} */

View File

@ -1,974 +0,0 @@
/*
* Copyright (C) 2016 Freie Universität Berlin
* 2017 OTA keys S.A.
*
* 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 cpu_stm32_common
* @{
*
* @file
* @brief Shared CPU specific definitions for the STM32 family
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Vincent Dupont <vincent@otakeys.com>
*/
#ifndef PERIPH_CPU_COMMON_H
#define PERIPH_CPU_COMMON_H
#include "cpu.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief CPU specific LSI clock speed
*/
#if defined(CPU_FAM_STM32F0) || defined (CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F3)
#define CLOCK_LSI (40000U)
#elif defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
#define CLOCK_LSI (37000U)
#elif defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \
defined(CPU_FAM_STM32F7) || defined(CPU_FAM_STM32L4) || \
defined(CPU_FAM_STM32WB)
#define CLOCK_LSI (32000U)
#else
#error "error: LSI clock speed not defined for your target CPU"
#endif
/**
* @brief Length of the CPU_ID in octets
*
* This is the same for all members of the stm32 family
*/
#define CPUID_LEN (12U)
/**
* @brief We provide our own pm_off() function for all STM32-based CPUs
*/
#define PROVIDES_PM_LAYERED_OFF
/**
* @brief All STM timers have 4 capture-compare channels
*/
#define TIMER_CHAN (4U)
/**
* @brief All STM QDEC timers have 2 capture channels
*/
#define QDEC_CHAN (2U)
/**
* @brief Use the shared SPI functions
* @{
*/
#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
#define PERIPH_SPI_NEEDS_TRANSFER_REG
#define PERIPH_SPI_NEEDS_TRANSFER_REGS
/** @} */
/**
* @name PM definitions
* @{
*/
/**
* @brief Number of usable low power modes
*/
#define PM_NUM_MODES (2U)
/**
* @name Power modes
* @{
*/
#define STM32_PM_STOP (1U)
#define STM32_PM_STANDBY (0U)
/** @} */
#ifndef PM_EWUP_CONFIG
/**
* @brief Wake-up pins configuration (CSR register)
*/
#define PM_EWUP_CONFIG (0U)
#endif
/** @} */
/**
* @name WDT upper and lower bound times in ms
* @{
*/
/* Actual Lower Limit is ~100us so round up */
#define NWDT_TIME_LOWER_LIMIT (1U)
#define NWDT_TIME_UPPER_LIMIT (4U * US_PER_MS * 4096U * (1 << 6U) \
/ CLOCK_LSI)
/* Once enabled wdt can't be stopped */
#define WDT_HAS_STOP (0U)
#if defined(CPU_FAM_STM32L4)
#define WDT_HAS_INIT (1U)
#else
#define WDT_HAS_INIT (0U)
#endif
/** @} */
/**
* @brief Available peripheral buses
*/
typedef enum {
APB1, /**< APB1 bus */
APB2, /**< APB2 bus */
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
APB12, /**< AHB1 bus, second register */
#endif
#if defined(CPU_FAM_STM32L0)
AHB, /**< AHB bus */
IOP, /**< IOP bus */
#elif defined(CPU_FAM_STM32L1) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3)
AHB, /**< AHB bus */
#elif defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \
defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32F7) || \
defined(CPU_FAM_STM32WB)
AHB1, /**< AHB1 bus */
AHB2, /**< AHB2 bus */
AHB3, /**< AHB3 bus */
#else
#warning "unsupported stm32XX family"
#endif
#if defined(CPU_FAM_STM32WB)
AHB4, /**< AHB4 bus */
#endif
} bus_t;
#ifndef DOXYGEN
/**
* @brief Overwrite the default gpio_t type definition
* @{
*/
#define HAVE_GPIO_T
typedef uint32_t gpio_t;
/** @} */
#endif
/**
* @brief Definition of a fitting UNDEF value
*/
#define GPIO_UNDEF (0xffffffff)
/**
* @brief Define a CPU specific GPIO pin generator macro
*/
#define GPIO_PIN(x, y) ((GPIOA_BASE + (x << 10)) | y)
/**
* @brief Define a magic number that tells us to use hardware chip select
*
* We use a random value here, that does clearly differentiate from any possible
* GPIO_PIN(x) value.
*/
#define SPI_HWCS_MASK (0xffffff00)
/**
* @brief Override the default SPI hardware chip select access macro
*
* Since the CPU does only support one single hardware chip select line, we can
* detect the usage of non-valid lines by comparing to SPI_HWCS_VALID.
*/
#define SPI_HWCS(x) (SPI_HWCS_MASK | x)
/**
* @name Use the shared I2C functions
* @{
*/
/** Use read reg function from periph common */
#define PERIPH_I2C_NEED_READ_REG
/** Use write reg function from periph common */
#define PERIPH_I2C_NEED_WRITE_REG
#define PERIPH_I2C_NEED_READ_REGS
#if defined(CPU_FAM_STM32F1) || defined(CPU_FAM_STM32F2) || \
defined(CPU_FAM_STM32L1) || defined(CPU_FAM_STM32F4)
#define PERIPH_I2C_NEED_WRITE_REGS
#endif
/** @} */
/**
* @brief Available MUX values for configuring a pin's alternate function
*/
typedef enum {
#ifdef CPU_FAM_STM32F1
GPIO_AF_OUT_PP = 0xb, /**< alternate function output - push-pull */
GPIO_AF_OUT_OD = 0xf, /**< alternate function output - open-drain */
#else
GPIO_AF0 = 0, /**< use alternate function 0 */
GPIO_AF1, /**< use alternate function 1 */
GPIO_AF2, /**< use alternate function 2 */
GPIO_AF3, /**< use alternate function 3 */
GPIO_AF4, /**< use alternate function 4 */
GPIO_AF5, /**< use alternate function 5 */
GPIO_AF6, /**< use alternate function 6 */
GPIO_AF7, /**< use alternate function 7 */
#ifndef CPU_FAM_STM32F0
GPIO_AF8, /**< use alternate function 8 */
GPIO_AF9, /**< use alternate function 9 */
GPIO_AF10, /**< use alternate function 10 */
GPIO_AF11, /**< use alternate function 11 */
GPIO_AF12, /**< use alternate function 12 */
GPIO_AF13, /**< use alternate function 13 */
GPIO_AF14, /**< use alternate function 14 */
GPIO_AF15 /**< use alternate function 15 */
#endif
#endif
} gpio_af_t;
#ifndef CPU_FAM_STM32F1
/**
* @brief Generate GPIO mode bitfields
*
* We use 5 bit to encode the mode:
* - bit 0+1: pin mode (input / output)
* - bit 2+3: pull resistor configuration
* - bit 4: output type (0: push-pull, 1: open-drain)
*/
#define GPIO_MODE(io, pr, ot) ((io << 0) | (pr << 2) | (ot << 4))
#ifndef DOXYGEN
/**
* @brief Override GPIO mode options
* @{
*/
#define HAVE_GPIO_MODE_T
typedef enum {
GPIO_IN = GPIO_MODE(0, 0, 0), /**< input w/o pull R */
GPIO_IN_PD = GPIO_MODE(0, 2, 0), /**< input with pull-down */
GPIO_IN_PU = GPIO_MODE(0, 1, 0), /**< input with pull-up */
GPIO_OUT = GPIO_MODE(1, 0, 0), /**< push-pull output */
GPIO_OD = GPIO_MODE(1, 0, 1), /**< open-drain w/o pull R */
GPIO_OD_PU = GPIO_MODE(1, 1, 1) /**< open-drain with pull-up */
} gpio_mode_t;
/** @} */
/**
* @brief Override flank configuration values
* @{
*/
#define HAVE_GPIO_FLANK_T
typedef enum {
GPIO_RISING = 1, /**< emit interrupt on rising flank */
GPIO_FALLING = 2, /**< emit interrupt on falling flank */
GPIO_BOTH = 3 /**< emit interrupt on both flanks */
} gpio_flank_t;
/** @} */
#endif /* ndef DOXYGEN */
#endif /* ndef CPU_FAM_STM32F1 */
#ifdef MODULE_PERIPH_DMA
/**
* @brief DMA configuration
*/
typedef struct {
/** DMA stream on stm32f2/4/7, channel on others
* STM32F2/4/7:
* - 0: DMA1 / Stream0
* - 1: DMA1 / Stream1
* - ...
* - 7: DMA1 / Stream7
* - 8: DAM2 / Stream0
* - ...
* - 15: DMA2 / Stream7
* STM32F0/1/L0/1/4:
* - 0: DMA1 / Channel1
* - ...
* - 4: DMA1 / Channel5
* - ...
* - 6: DMA1 / Channel7
* - 7: Reserved
* - 8: DMA2 / Channel1
* - ...
* - 12: DMA2 / Channel5
* - ...
* - 14: DMA2 / Channel7
*/
int stream;
} dma_conf_t;
/**
* @brief DMA type
*/
typedef unsigned dma_t;
/**
* @brief DMA modes
*/
typedef enum {
DMA_PERIPH_TO_MEM, /**< Peripheral to memory */
DMA_MEM_TO_PERIPH, /**< Memory to peripheral */
DMA_MEM_TO_MEM, /**< Memory to memory */
} dma_mode_t;
/**
* @name DMA Increment modes
* @{
*/
#define DMA_INC_SRC_ADDR (0x01)
#define DMA_INC_DST_ADDR (0x02)
#define DMA_INC_BOTH_ADDR (DMA_INC_SRC_ADDR | DMA_INC_DST_ADDR)
/** @} */
/**
* @name DMA data width
* @{
*/
#define DMA_DATA_WIDTH_BYTE (0x00)
#define DMA_DATA_WIDTH_HALF_WORD (0x04)
#define DMA_DATA_WIDTH_WORD (0x08)
#define DMA_DATA_WIDTH_MASK (0x0C)
#define DMA_DATA_WIDTH_SHIFT (2)
/** @} */
#endif /* MODULE_PERIPH_DMA */
/**
* @brief DAC line configuration data
*/
typedef struct {
gpio_t pin; /**< pin connected to the line */
uint8_t chan; /**< DAC device used for this line */
} dac_conf_t;
/**
* @brief Timer configuration
*/
typedef struct {
TIM_TypeDef *dev; /**< timer device */
uint32_t max; /**< maximum value to count to (16/32 bit) */
uint32_t rcc_mask; /**< corresponding bit in the RCC register */
uint8_t bus; /**< APBx bus the timer is clock from */
uint8_t irqn; /**< global IRQ channel */
} timer_conf_t;
/**
* @brief PWM channel
*/
typedef struct {
gpio_t pin; /**< GPIO pin mapped to this channel */
uint8_t cc_chan; /**< capture compare channel used */
} pwm_chan_t;
/**
* @brief PWM configuration
*/
typedef struct {
TIM_TypeDef *dev; /**< Timer used */
uint32_t rcc_mask; /**< bit in clock enable register */
pwm_chan_t chan[TIMER_CHAN]; /**< channel mapping, set to {GPIO_UNDEF, 0}
* if not used */
gpio_af_t af; /**< alternate function used */
uint8_t bus; /**< APB bus */
} pwm_conf_t;
/**
* @brief QDEC channel
*/
typedef struct {
gpio_t pin; /**< GPIO pin mapped to this channel */
uint8_t cc_chan; /**< capture compare channel used */
} qdec_chan_t;
/**
* @brief QDEC configuration
*/
typedef struct {
TIM_TypeDef *dev; /**< Timer used */
uint32_t max; /**< Maximum counter value */
uint32_t rcc_mask; /**< bit in clock enable register */
qdec_chan_t chan[QDEC_CHAN]; /**< channel mapping, set to {GPIO_UNDEF, 0}
* if not used */
gpio_af_t af; /**< alternate function used */
uint8_t bus; /**< APB bus */
uint8_t irqn; /**< global IRQ channel */
} qdec_conf_t;
/**
* @brief UART hardware module types
*/
typedef enum {
STM32_USART, /**< STM32 USART module type */
STM32_LPUART, /**< STM32 Low-power UART (LPUART) module type */
} uart_type_t;
#ifndef DOXYGEN
/**
* @brief Invalid UART mode mask
*
* This mask is also used to force data_bits_t to be uint32_t type
* since it may be assigned a uint32_t variable in uart_mode
*/
#define UART_INVALID_MODE (0x8000000)
/**
* @brief Override parity values
* @{
*/
#define HAVE_UART_PARITY_T
typedef enum {
UART_PARITY_NONE = 0, /**< no parity */
UART_PARITY_EVEN = USART_CR1_PCE, /**< even parity */
UART_PARITY_ODD = (USART_CR1_PCE | USART_CR1_PS), /**< odd parity */
UART_PARITY_MARK = UART_INVALID_MODE | 4, /**< not supported */
UART_PARITY_SPACE = UART_INVALID_MODE | 5 /**< not supported */
} uart_parity_t;
/** @} */
/**
* @brief Override data bits length values
* @{
*/
#define HAVE_UART_DATA_BITS_T
typedef enum {
UART_DATA_BITS_5 = UART_INVALID_MODE | 1, /**< not supported */
UART_DATA_BITS_6 = UART_INVALID_MODE | 2, /**< not supported unless parity is set */
#if defined(USART_CR1_M1)
UART_DATA_BITS_7 = USART_CR1_M1, /**< 7 data bits */
#else
UART_DATA_BITS_7 = UART_INVALID_MODE | 3, /**< not supported unless parity is set */
#endif
UART_DATA_BITS_8 = 0, /**< 8 data bits */
} uart_data_bits_t;
/** @} */
/**
* @brief Override stop bits length values
* @{
*/
#define HAVE_UART_STOP_BITS_T
typedef enum {
UART_STOP_BITS_1 = 0, /**< 1 stop bit */
UART_STOP_BITS_2 = USART_CR2_STOP_1, /**< 2 stop bits */
} uart_stop_bits_t;
/** @} */
#endif /* ndef DOXYGEN */
/**
* @brief Structure for UART configuration data
*/
typedef struct {
USART_TypeDef *dev; /**< UART device base register address */
uint32_t rcc_mask; /**< bit in clock enable register */
gpio_t rx_pin; /**< RX pin */
gpio_t tx_pin; /**< TX pin */
#ifndef CPU_FAM_STM32F1
gpio_af_t rx_af; /**< alternate function for RX pin */
gpio_af_t tx_af; /**< alternate function for TX pin */
#endif
uint8_t bus; /**< APB bus */
uint8_t irqn; /**< IRQ channel */
#ifdef MODULE_PERIPH_UART_HW_FC
gpio_t cts_pin; /**< CTS pin - set to GPIO_UNDEF when not using HW flow control */
gpio_t rts_pin; /**< RTS pin */
#ifndef CPU_FAM_STM32F1
gpio_af_t cts_af; /**< alternate function for CTS pin */
gpio_af_t rts_af; /**< alternate function for RTS pin */
#endif
#endif
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L4) || \
defined(CPU_FAM_STM32WB)
uart_type_t type; /**< hardware module type (USART or LPUART) */
uint32_t clk_src; /**< clock source used for UART */
#endif
#ifdef MODULE_PERIPH_DMA
dma_t dma; /**< Logical DMA stream used for TX */
uint8_t dma_chan; /**< DMA channel used for TX */
#endif
} uart_conf_t;
/**
* @brief Structure for SPI configuration data
*/
typedef struct {
SPI_TypeDef *dev; /**< SPI device base register address */
gpio_t mosi_pin; /**< MOSI pin */
gpio_t miso_pin; /**< MISO pin */
gpio_t sclk_pin; /**< SCLK pin */
gpio_t cs_pin; /**< HWCS pin, set to GPIO_UNDEF if not mapped */
#ifndef CPU_FAM_STM32F1
gpio_af_t mosi_af; /**< MOSI pin alternate function */
gpio_af_t miso_af; /**< MISO pin alternate function */
gpio_af_t sclk_af; /**< SCLK pin alternate function */
gpio_af_t cs_af; /**< HWCS pin alternate function */
#endif
uint32_t rccmask; /**< bit in the RCC peripheral enable register */
uint8_t apbbus; /**< APBx bus the device is connected to */
#ifdef MODULE_PERIPH_DMA
dma_t tx_dma; /**< Logical DMA stream used for TX */
uint8_t tx_dma_chan; /**< DMA channel used for TX */
dma_t rx_dma; /**< Logical DMA stream used for RX */
uint8_t rx_dma_chan; /**< DMA channel used for RX */
#endif
} spi_conf_t;
#ifndef DOXYGEN
/**
* @brief Default mapping of I2C bus speed values
* @{
*/
#define HAVE_I2C_SPEED_T
typedef enum {
#if defined(CPU_FAM_STM32F1) || defined(CPU_FAM_STM32F2) || \
defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32L1)
I2C_SPEED_LOW, /**< low speed mode: ~10kit/s */
#endif
I2C_SPEED_NORMAL, /**< normal mode: ~100kbit/s */
I2C_SPEED_FAST, /**< fast mode: ~400kbit/s */
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3) || \
defined(CPU_FAM_STM32F7) || defined(CPU_FAM_STM32L0) || \
defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
I2C_SPEED_FAST_PLUS, /**< fast plus mode: ~1Mbit/s */
#endif
} i2c_speed_t;
/** @} */
#endif /* ndef DOXYGEN */
/**
* @brief Structure for I2C configuration data
*/
typedef struct {
I2C_TypeDef *dev; /**< i2c device */
i2c_speed_t speed; /**< i2c bus speed */
gpio_t scl_pin; /**< scl pin number */
gpio_t sda_pin; /**< sda pin number */
#ifndef CPU_FAM_STM32F1
gpio_af_t scl_af; /**< scl pin alternate function value */
gpio_af_t sda_af; /**< sda pin alternate function value */
#endif
uint8_t bus; /**< APB bus */
uint32_t rcc_mask; /**< bit in clock enable register */
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3)
uint32_t rcc_sw_mask; /**< bit to switch I2C clock */
#endif
#if defined(CPU_FAM_STM32F1) || defined(CPU_FAM_STM32F2) || \
defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32L1)
uint32_t clk; /**< bus frequency as defined in board config */
#endif
uint8_t irqn; /**< I2C event interrupt number */
} i2c_conf_t;
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3) || \
defined(CPU_FAM_STM32F7) || defined(CPU_FAM_STM32L0) || \
defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
/**
* @brief Structure for I2C timing register settings
*
* These parameters are valid for 48MHz (16MHz for L0) input clock.
* See reference manual of supported CPU for example of timing settings:
* - STM32F030/F070: see RM0360, section 22.4.10, p.560, table 76
* - STM32F303: see RM0316, section 28.4.9, p.849, table 148
* - STM32F72X: see RM0431, section 26.4.9, p.851, table 149
* - STM32L0x2: see RM0376, section 27.4.10, p.686, table 117
* - STM32L4X5/6: see RM0351, section 39.4.9, p.1297, table 234
*/
typedef struct {
uint8_t presc; /**< Timing prescaler value */
uint8_t scll; /**< SCL Low period */
uint8_t sclh; /**< SCL High period */
uint8_t sdadel; /**< Data hold time */
uint8_t scldel; /**< Data setup time */
} i2c_timing_param_t;
#endif
/**
* @brief USB OTG peripheral type.
*
* High speed peripheral is assumed to have DMA support available.
*
* @warning Only one of each type is supported at the moment, it is not
* supported to have two FS type or two HS type peripherals enabled on a
* single MCU.
*/
typedef enum {
STM32_USB_OTG_FS = 0, /**< Full speed peripheral */
STM32_USB_OTG_HS = 1, /**< High speed peripheral */
} stm32_usb_otg_fshs_type_t;
/**
* @brief Type of USB OTG peripheral phy.
*
* The FS type only supports the built-in type, the HS phy can have either the
* FS built-in phy enabled or the HS ULPI interface enabled.
*/
typedef enum {
STM32_USB_OTG_PHY_BUILTIN,
STM32_USB_OTG_PHY_ULPI,
} stm32_usb_otg_fshs_phy_t;
/**
* @brief stm32 USB OTG configuration
*/
typedef struct {
uint8_t *periph; /**< USB peripheral base address */
uint32_t rcc_mask; /**< bit in clock enable register */
stm32_usb_otg_fshs_phy_t phy; /**< Built-in or ULPI phy */
stm32_usb_otg_fshs_type_t type; /**< FS or HS type */
uint8_t irqn; /**< IRQ channel */
uint8_t ahb; /**< AHB bus */
gpio_t dm; /**< Data- gpio */
gpio_t dp; /**< Data+ gpio */
gpio_af_t af; /**< Alternative function */
} stm32_usb_otg_fshs_config_t;
/**
* @brief Get the actual bus clock frequency for the APB buses
*
* @param[in] bus target APBx bus
*
* @return bus clock frequency in Hz
*/
uint32_t periph_apb_clk(uint8_t bus);
/**
* @brief Get the actual timer clock frequency
*
* @param[in] bus corresponding APBx bus
*
* @return timer clock frequency in Hz
*/
uint32_t periph_timer_clk(uint8_t bus);
/**
* @brief Enable the given peripheral clock
*
* @param[in] bus bus the peripheral is connected to
* @param[in] mask bit in the RCC enable register
*/
void periph_clk_en(bus_t bus, uint32_t mask);
/**
* @brief Disable the given peripheral clock
*
* @param[in] bus bus the peripheral is connected to
* @param[in] mask bit in the RCC enable register
*/
void periph_lpclk_dis(bus_t bus, uint32_t mask);
/**
* @brief Enable the given peripheral clock in low power mode
*
* @param[in] bus bus the peripheral is connected to
* @param[in] mask bit in the RCC enable register
*/
void periph_lpclk_en(bus_t bus, uint32_t mask);
/**
* @brief Disable the given peripheral clock in low power mode
*
* @param[in] bus bus the peripheral is connected to
* @param[in] mask bit in the RCC enable register
*/
void periph_clk_dis(bus_t bus, uint32_t mask);
/**
* @brief Configure the alternate function for the given pin
*
* @param[in] pin pin to configure
* @param[in] af alternate function to use
*/
void gpio_init_af(gpio_t pin, gpio_af_t af);
/**
* @brief Configure the given pin to be used as ADC input
*
* @param[in] pin pin to configure
*/
void gpio_init_analog(gpio_t pin);
#ifdef MODULE_PERIPH_DMA
/**
* @brief DMA stream not defined
*/
#define DMA_STREAM_UNDEF (UINT_MAX)
/**
* @brief Initialize DMA
*/
void dma_init(void);
/**
* @brief Execute a DMA transfer
*
* This function blocks until the transfer is completed. This is a convenience
* function which configure, start, wait and stop a DMA transfer.
*
* @param[in] dma logical DMA stream
* @param[in] chan DMA channel (on stm32f2/4/7, CxS or unused on others)
* @param[in] src source buffer
* @param[out] dst destination buffer
* @param[in] len length to transfer
* @param[in] mode DMA mode
* @param[in] flags DMA configuration
*
* @return < 0 on error, the number of transferred bytes otherwise
*/
int dma_transfer(dma_t dma, int chan, const volatile void *src, volatile void *dst, size_t len,
dma_mode_t mode, uint8_t flags);
/**
* @brief Acquire a DMA stream
*
* @param[in] dma logical DMA stream
*/
void dma_acquire(dma_t dma);
/**
* @brief Release a DMA stream
*
* @param[in] dma logical DMA stream
*/
void dma_release(dma_t dma);
/**
* @brief Start a DMA transfer on a stream
*
* Start a DMA transfer on a given stream. The stream must be configured first
* by a @p dma_configure call.
*
* @param[in] dma logical DMA stream
*/
void dma_start(dma_t dma);
/**
* @brief Suspend a DMA transfer on a stream
*
* @param[in] dma logical DMA stream
*
* @return the remaining number of bytes to transfer
*/
uint16_t dma_suspend(dma_t dma);
/**
* @brief Resume a suspended DMA transfer on a stream
*
* @param[in] dma logical DMA stream
* @param[in] reamaining the remaining number of bytes to transfer
*/
void dma_resume(dma_t dma, uint16_t remaining);
/**
* @brief Stop a DMA transfer on a stream
*
* @param[in] dma logical DMA stream
*/
void dma_stop(dma_t dma);
/**
* @brief Wait for the end of a transfer
*
* @param[in] dma logical DMA stream
*/
void dma_wait(dma_t dma);
/**
* @brief Configure a DMA stream for a new transfer
*
* @param[in] dma logical DMA stream
* @param[in] chan DMA channel (on stm32f2/4/7, CxS or unused on others)
* @param[in] src source buffer
* @param[out] dst destination buffer
* @param[in] len length to transfer
* @param[in] mode DMA mode
* @param[in] flags DMA configuration
*
* @return < 0 on error, 0 on success
*/
int dma_configure(dma_t dma, int chan, const volatile void *src, volatile void *dst, size_t len,
dma_mode_t mode, uint8_t flags);
#endif /* MODULE_PERIPH_DMA */
#ifdef MODULE_PERIPH_CAN
#include "candev_stm32.h"
#endif
#ifdef MODULE_PERIPH_USBDEV
#include "usbdev_stm32.h"
#endif
/**
* @brief STM32 Ethernet configuration mode
*/
typedef enum {
MII = 18, /**< Configuration for MII */
RMII = 9, /**< Configuration for RMII */
SMI = 2, /**< Configuration for SMI */
} eth_mode_t;
/**
* @brief STM32 Ethernet speed options
*/
typedef enum {
ETH_SPEED_10T_HD = 0x0000,
ETH_SPEED_10T_FD = 0x0100,
ETH_SPEED_100TX_HD = 0x2000,
ETH_SPEED_100TX_FD = 0x2100,
} eth_speed_t;
/**
* @brief Ethernet Peripheral configuration
*/
typedef struct {
eth_mode_t mode; /**< Select configuration mode */
char mac[6]; /**< Ethernet MAC address */
eth_speed_t speed; /**< Speed selection */
uint8_t dma; /**< Locical CMA Descriptor used for TX */
uint8_t dma_chan; /**< DMA channel used for TX */
char phy_addr; /**< PHY address */
gpio_t pins[]; /**< Pins to use. MII requires 18 pins,
RMII 9 and SMI 9. Not all speeds are
supported by all modes. */
} eth_conf_t;
/**
* @name Ethernet PHY Common Registers
* @{
*/
#define PHY_BMCR (0x00)
#define PHY_BSMR (0x01)
#define PHY_PHYIDR1 (0x02)
#define PHY_PHYIDR2 (0x03)
#define PHY_ANAR (0x04)
#define PHY_ANLPAR (0x05)
#define PHY_ANER (0x06)
#define PHY_ANNPTR (0x07)
/** @} */
/**
* @name Ethernet PHY BMCR Fields
* @{
*/
#define BMCR_RESET (0x8000)
#define BMCR_LOOPBACK (0x4000)
#define BMCR_SPEED_SELECT (0x2000)
#define BMCR_AN (0x1000)
#define BMCR_POWER_DOWN (0x0800)
#define BMCR_ISOLATE (0x0400)
#define BMCR_RESTART_AN (0x0200)
#define BMCR_DUPLEX_MODE (0x0100)
#define BMCR_COLLISION_TEST (0x0080)
/** @} */
/**
* @name Ethernet PHY BSMR Fields
* @{
*/
#define BSMR_100BASE_T4 (0x8000)
#define BSMR_100BASE_TX_FDUPLEX (0x4000)
#define BSMR_100BASE_TX_HDUPLEX (0x2000)
#define BSMR_10BASE_T_FDUPLEX (0x1000)
#define BSMR_10BASE_T_HDUPLEX (0x0800)
#define BSMR_NO_PREAMBLE (0x0040)
#define BSMR_AN_COMPLETE (0x0020)
#define BSMR_REMOTE_FAULT (0x0010)
#define BSMR_AN_ABILITY (0x0008)
#define BSMR_LINK_STATUS (0x0004)
#define BSMR_JABBER_DETECT (0x0002)
#define BSMR_EXTENDED_CAP (0x0001)
/** @} */
/**
* @name Ethernet PHY PHYIDR1 Fields
*/
#define PHYIDR1_OUI (0xffff)
/**
* @name Ethernet PHY PHYIDR2 Fields
* @{
*/
#define PHYIDR2_OUI (0xfe00)
#define PHYIDR2_MODEL (0x01f0)
#define PHYIDR2_REV (0x0007)
/** @} */
/**
* @name Ethernet PHY ANAR Fields
* @{
*/
#define ANAR_NEXT_PAGE (0x8000)
#define ANAR_REMOTE_FAULT (0x2000)
#define ANAR_PAUSE (0x0600)
#define ANAR_100BASE_T4 (0x0200)
#define ANAR_100BASE_TX_FDUPLEX (0x0100)
#define ANAR_100BASE_TX_HDUPLEX (0x0080)
#define ANAR_10BASE_T_FDUPLEX (0x0040)
#define ANAR_10BASE_T_HDUPLEX (0x0020)
#define ANAR_SELECTOR (0x000f)
/** @} */
/**
* @name Ethernet PHY ANLPAR Fields
* @{
*/
#define ANLPAR_NEXT_PAGE (0x8000)
#define ANLPAR_ACK (0x4000)
#define ANLPAR_REMOTE_FAULT (0x2000)
#define ANLPAR_PAUSE (0x0600)
#define ANLPAR_100BASE_T4 (0x0200)
#define ANLPAR_100BASE_TX_FDUPLEX (0x0100)
#define ANLPAR_100BASE_TX_HDUPLEX (0x0080)
#define ANLPAR_10BASE_T_FDUPLEX (0x0040)
#define ANLPAR_10BASE_T_HDUPLEX (0x0020)
#define ANLPAR_SELECTOR (0x000f)
/** @} */
/**
* @name Ethernet PHY ANNPTR Fields
* @{
*/
#define ANNPTR_NEXT_PAGE (0x8000)
#define ANNPTR_MSG_PAGE (0x2000)
#define ANNPTR_ACK2 (0x1000)
#define ANNPTR_TOGGLE_TX (0x0800)
#define ANNPTR_CODE (0x03ff)
/** @} */
/**
* @name Ethernet PHY ANER Fields
* @{
*/
#define ANER_PDF (0x0010)
#define ANER_LP_NEXT_PAGE_ABLE (0x0008)
#define ANER_NEXT_PAGE_ABLE (0x0004)
#define ANER_PAGE_RX (0x0002)
#define ANER_LP_AN_ABLE (0x0001)
/** @} */
#ifdef MODULE_STM32_ETH
/**
* @brief Read a PHY register
*
* @param[in] addr address of the PHY to read
* @param[in] reg register to be read
*
* @return value in the register, or <=0 on error
*/
int32_t stm32_eth_phy_read(uint16_t addr, uint8_t reg);
/**
* @brief Write a PHY register
*
* @param[in] addr address of the PHY to write
* @param[in] reg register to be written
* @param[in] value value to write into the register
*
* @return 0 in case of success or <=0 on error
*/
int32_t stm32_eth_phy_write(uint16_t addr, uint8_t reg, uint16_t value);
#endif /* MODULE_STM32_ETH */
#ifdef __cplusplus
}
#endif
#endif /* PERIPH_CPU_COMMON_H */
/** @} */

View File

@ -1,92 +0,0 @@
/*
* Copyright (C) 2017 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.
*/
/**
* @ingroup cpu_stm32_common
* @{
*
* @file
* @brief Interface for configuring the clock tree of STM32 CPUs
*
* @todo This interface should probably be moved and implemented for
* every STM32 CPU
*
* @author Hauke Petersen <hauke.pertersen@fu-berlin.de>
*/
#ifndef STMCLK_H
#define STMCLK_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Configure the high speed clock domain (main system clock)
*
* This function initializes and configures the main systems clock(s). For this,
* the following actions are carried out:
* - enable the HSI
* - use the HSI as system clock (so now we are always in a defined state)
* - configure flash wait states and AHB/APB bus dividers
* - [opt] enable the HSE / MSI
* - configure the PLL
* - use PLL as system clock
* - turn off the HSI if unused
*
* All of these options are configurable through the board's periph_conf.h
*/
void stmclk_init_sysclk(void);
/**
* @brief Enable the internal high speed clock (HSI)
*/
void stmclk_enable_hsi(void);
/**
* @brief Disable the internal high speed clock (HSI)
*
* @note The HSI is only disabled, if it is at that point not used to drive
* the system clock or the PLL
*/
void stmclk_disable_hsi(void);
/**
* @brief Configure and enable the low speed clock domain
*
* The actual clock used as input for the low frequency clock can be either the
* external low speed clock (LSE) or the internal low speed clock (LSI). This
* is configured in the board's periph_conf.h file.
*/
void stmclk_enable_lfclk(void);
/**
* @brief Disable the low frequency clock domain
*
* @note When calling this function, better know what you do: be sure that
* the clock is not needed by any peripheral before calling this
* function.
*/
void stmclk_disable_lfclk(void);
/**
* @brief Unlock write access to the backup domain control
*/
void stmclk_dbp_unlock(void);
/**
* @brief Lock write access to backup control domain
*/
void stmclk_dbp_lock(void);
#ifdef __cplusplus
}
#endif
#endif /* STMCLK_H */
/** @} */

View File

@ -1,138 +0,0 @@
/*
* Copyright (C) 2019 Koen Zandberg
*
* 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.
*/
/**
* @defgroup cpu_stm32_common_usbdev stm32 USB OTG FS/HS peripheral
* @ingroup cpu_stm32_common
* @brief USB interface functions for the stm32 class devices
*
* @{
*
* @file
* @brief USB interface functions for the stm32 OTG FS/HS class devices
*
* The stm32f2, stm32f4 and stm32f7 have a common USB OTG FS capable USB
* peripheral.
*
* Two versions are currently known to exist with subtle differences
* in some registers. The CID register of the peripheral indicates this version,
* 0x00001200 for one version of the full speed peripheral and 0x00002000 for
* the other version of the full speed peripheral.
* The main difference is in the GCCFG register, where the 1.2 version has a
* NOVBUSSENS bit and the 2.0 version has a VBDEN bit. This difference is used
* to detect the IP version.
* The 2.0 version also has more advanced USB low power mode support.
*
* For the end user, the main difference is the 1.2 version having 4 endpoints
* and the 2.0 version having 6 endpoints. The 2.0 version also supports a
* number of USB low power modes.
*
* @author Koen Zandberg <koen@bergzand.net>
*/
#ifndef USBDEV_STM32_H
#define USBDEV_STM32_H
#include <stdint.h>
#include <stdlib.h>
#include "periph_cpu.h"
#include "periph/usbdev.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Detect the IP version based on the available register define */
#if defined(USB_OTG_GCCFG_NOVBUSSENS)
#define STM32_USB_OTG_CID_1x /**< USB OTG FS version 0x00001200 */
#elif defined(USB_OTG_GCCFG_VBDEN)
#define STM32_USB_OTG_CID_2x /**< USB OTG FS version 0x00002000 */
#else
#error Unknown USB peripheral version
#endif
/**
* @brief Buffer space available for endpoint TX/RX data
*/
#ifndef STM32_USB_OTG_BUF_SPACE
#define STM32_USB_OTG_BUF_SPACE USBDEV_EP_BUF_SPACE
#endif
/**
* @brief Number of endpoints available with the OTG FS peripheral
* including the control endpoint
*/
#ifdef STM32_USB_OTG_CID_1x
#define STM32_USB_OTG_FS_NUM_EP (4) /**< OTG FS with 4 endpoints */
#elif defined(STM32_USB_OTG_CID_2x)
#define STM32_USB_OTG_FS_NUM_EP (6) /**< OTG FS with 6 endpoints */
#endif
/**
* @brief Number of endpoints available with the OTG HS peripheral
* including the control endpoint
*/
#ifdef STM32_USB_OTG_CID_1x
#define STM32_USB_OTG_HS_NUM_EP (6) /**< OTG HS with 6 endpoints */
#elif defined(STM32_USB_OTG_CID_2x)
#define STM32_USB_OTG_HS_NUM_EP (9) /**< OTG HS with 9 endpoints */
#endif
/**
* @brief USB OTG FS FIFO reception buffer space in 32-bit words
*
* Used as shared FIFO for reception of all OUT transfers
*
* @note The application might have to increase this when dealing with large
* isochronous transfers
*/
#ifndef STM32_USB_OTG_FS_RX_FIFO_SIZE
#define STM32_USB_OTG_FS_RX_FIFO_SIZE (128U)
#endif
/**
* @brief USB OTG HS FIFO reception buffer space in 32-bit words
*
* Used as shared FIFO for reception of all OUT transfers from the host
*/
#ifndef STM32_USB_OTG_HS_RX_FIFO_SIZE
#define STM32_USB_OTG_HS_RX_FIFO_SIZE (512U)
#endif
/**
* @brief Use the built-in DMA controller of the HS peripheral when possible
*/
#ifndef STM32_USB_OTG_HS_USE_DMA
#ifdef STM32_USB_OTG_CID_1x
/* FIXME: It should be possible to use DMA with the 1.x version of the *
* peripheral, but somehow it doesn't work. */
#define STM32_USB_OTG_HS_USE_DMA (0)
#else
#define STM32_USB_OTG_HS_USE_DMA (1)
#endif
#endif
/**
* @brief stm32 USB OTG peripheral device context
*/
typedef struct {
usbdev_t usbdev; /**< Inherited usbdev struct */
const stm32_usb_otg_fshs_config_t *config; /**< USB peripheral config */
uint8_t buffer[STM32_USB_OTG_BUF_SPACE]; /**< Buffer space for endpoints */
size_t occupied; /**< Buffer space occupied */
size_t fifo_pos; /**< FIFO space occupied */
usbdev_ep_t *in; /**< In endpoints */
usbdev_ep_t *out; /**< Out endpoints */
bool suspend; /**< Suspend status */
} stm32_usb_otg_fshs_t;
#ifdef __cplusplus
}
#endif
#endif /* USBDEV_STM32_H */
/** @} */

View File

@ -1,28 +0,0 @@
/*
* Copyright (C) 2017 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.
*/
/**
* @addtogroup cpu_cortexm_common
* @{
*
* @file
* @brief Memory definitions for the Cortex-M family
*
* @author Francisco Acosta <francisco.acosta@inria.fr>
*
* @}
*/
ccmram_length = DEFINED( ccmram_len ) ? ccmram_len : 0x0 ;
MEMORY
{
ccmram : ORIGIN = 0x10000000, LENGTH = ccmram_length
}
INCLUDE cortexm.ld

View File

@ -1,23 +0,0 @@
MODULE = stm32_common_periph
# Select the specific implementation for `periph_i2c`
ifneq (,$(filter periph_i2c,$(USEMODULE)))
ifneq (,$(filter $(CPU),stm32f0 stm32f3 stm32f7 stm32l0 stm32l4 stm32wb))
SRC += i2c_1.c
else # stm32f1/f2/f4/l1
SRC += i2c_2.c
endif
endif
# flashpage and eeprom periph implementations share flash lock/unlock functions
# defined in flash_common.c
ifneq (,$(filter periph_flashpage periph_eeprom,$(USEMODULE)))
SRC += flash_common.c
endif
ifneq (,$(filter periph_wdt,$(USEMODULE)))
$(warning Attention! WDT is clocked by CLOCK_LSI, it needs manual measuring\
since values can deviate up to 50% from reference)
endif
include $(RIOTMAKE)/periph.mk

File diff suppressed because it is too large Load Diff

View File

@ -1,123 +0,0 @@
/*
* Copyright (C) 2014 Simon Brummer
* 2015-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.
*/
/**
* @ingroup cpu_stm32_common
* @ingroup drivers_periph_dac
* @{
*
* @file
* @brief Low-level DAC driver implementation
*
* @author Simon Brummer <simon.brummer@haw-hamburg.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include "cpu.h"
#include "assert.h"
#include "periph/dac.h"
/* DAC channel enable bits */
#ifdef DAC_CR_EN2
#define EN_MASK (DAC_CR_EN1 | DAC_CR_EN2)
#else
#define EN_MASK (DAC_CR_EN1)
#endif
/* get RCC bit */
#ifdef RCC_APB1ENR_DAC1EN
#define RCC_BIT (RCC_APB1ENR_DAC1EN)
#else
#define RCC_BIT (RCC_APB1ENR_DACEN)
#endif
/* deduct DAC device from given line channel */
static inline DAC_TypeDef *dev(dac_t line)
{
#if defined(DAC2)
return (dac_config[line].chan > 1) ? DAC2 : DAC1;
#elif defined (DAC1)
(void) line;
return DAC1;
#else
(void) line;
return DAC;
#endif
}
int8_t dac_init(dac_t line)
{
if (line >= DAC_NUMOF) {
return DAC_NOLINE;
}
/* configure pin */
gpio_init_analog(dac_config[line].pin);
/* reset output and enable the line's channel */
dac_poweron(line);
dac_set(line, 0);
return DAC_OK;
}
void dac_set(dac_t line, uint16_t value)
{
assert(line < DAC_NUMOF);
/* scale set value to 12-bit */
value = (value >> 4);
#ifdef DAC_DHR12R2_DACC2DHR
if (dac_config[line].chan & 0x01) {
dev(line)->DHR12R2 = value;
}
else {
dev(line)->DHR12R1 = value;
}
#else
dev(line)->DHR12R1 = value;
#endif
}
void dac_poweron(dac_t line)
{
assert(line < DAC_NUMOF);
/* enable the DAC's clock */
#if defined(DAC2)
periph_clk_en(APB1, (dac_config[line].chan > 1) ?
RCC_APB1ENR_DAC2EN : RCC_APB1ENR_DAC1EN);
#else
periph_clk_en(APB1, RCC_BIT);
#endif
/* enable corresponding DAC channel */
dev(line)->CR |= (1 << (16 * (dac_config[line].chan & 0x01)));
}
void dac_poweroff(dac_t line)
{
assert(line < DAC_NUMOF);
/* disable corresponding channel */
dev(line)->CR &= ~(1 << (16 * (dac_config[line].chan & 0x01)));
/* disable the DAC's clock in case no channel is active anymore */
if (!(dev(line)->CR & EN_MASK)) {
#if defined(DAC2)
periph_clk_dis(APB1, (dac_config[line].chan > 1) ?
RCC_APB1ENR_DAC2EN : RCC_APB1ENR_DAC1EN);
#else
periph_clk_dis(APB1, RCC_BIT);
#endif
}
}

View File

@ -1,599 +0,0 @@
/*
* Copyright (C) 2017 OTA keys S.A.
*
* 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 cpu_stm32_common
* @{
*
* @file
* @brief Low-level DMA driver implementation
*
* @author Vincent Dupont <vincent@otakeys.com>
*
* @}
*/
#include <stdint.h>
#include "periph_cpu.h"
#include "periph_conf.h"
#include "mutex.h"
#include "assert.h"
#include "pm_layered.h"
#if CPU_FAM_STM32F3
#error "DMA is not supported on STM32F3"
#endif
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
#define STM32_DMA_Stream_Type DMA_Stream_TypeDef
#define CLOCK AHB1
#define PERIPH_ADDR PAR
#define MEM_ADDR M0AR
#define NDTR_REG NDTR
#define CONTROL_REG CR
#define RCC_MASK_DMA1 RCC_AHB1ENR_DMA1EN
#define RCC_MASK_DMA2 RCC_AHB1ENR_DMA2EN
#define DMA_STREAM_IT_MASK (DMA_LISR_FEIF0 | DMA_LISR_DMEIF0 | \
DMA_LISR_TEIF0 | DMA_LISR_HTIF0 | \
DMA_LISR_TCIF0)
#define DMA_EN DMA_SxCR_EN
#else /* CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7 */
#define STM32_DMA_Stream_Type DMA_Channel_TypeDef
#if CPU_FAM_STM32L4
#define CLOCK AHB1
#define RCC_MASK_DMA1 RCC_AHB1ENR_DMA1EN
#define RCC_MASK_DMA2 RCC_AHB1ENR_DMA2EN
#else /* CPU_FAM_STM32L4 */
#define CLOCK AHB
#if CPU_FAM_STM32F1 || CPU_FAM_STM32L1
#define RCC_MASK_DMA1 RCC_AHBENR_DMA1EN
#else /* CPU_FAM_STM32F1 || CPU_FAM_STM32L1 */
#define RCC_MASK_DMA1 RCC_AHBENR_DMAEN
#endif /* CPU_FAM_STM32F1 || CPU_FAM_STM32L1 */
#define RCC_MASK_DMA2 RCC_AHBENR_DMA2EN
#endif /* CPU_FAM_STM32L4 */
#define PERIPH_ADDR CPAR
#define MEM_ADDR CMAR
#define NDTR_REG CNDTR
#define CONTROL_REG CCR
#define DMA_EN DMA_CCR_EN
#define DMA_STREAM_IT_MASK (DMA_IFCR_CGIF1 | DMA_IFCR_CTCIF1 | \
DMA_IFCR_CHTIF1 | DMA_IFCR_CTEIF1)
#ifndef DMA_CCR_MSIZE_Pos
#define DMA_CCR_MSIZE_Pos (10)
#endif
#ifndef DMA_CCR_PSIZE_Pos
#define DMA_CCR_PSIZE_Pos (8)
#endif
#ifndef DMA_CCR_MINC_Pos
#define DMA_CCR_MINC_Pos (7)
#endif
#ifndef DMA_CCR_PINC_Pos
#define DMA_CCR_PINC_Pos (6)
#endif
#ifndef DMA_CCR_DIR_Pos
#define DMA_CCR_DIR_Pos (4)
#endif
#ifndef DMA_CCR_MEM2MEM_Pos
#define DMA_CCR_MEM2MEM_Pos (14)
#endif
#if defined(CPU_FAM_STM32F0) && !defined(DMA1_Channel4_5_6_7_IRQn)
#define DMA1_Channel4_5_6_7_IRQn DMA1_Channel4_5_IRQn
#endif
#endif /* CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7 */
struct dma_ctx {
mutex_t conf_lock;
mutex_t sync_lock;
uint16_t len;
};
static struct dma_ctx dma_ctx[DMA_NUMOF];
/**
* @brief Get DMA base register
*
* For simplifying DMA stream handling, we map the DMA channels transparently to
* one integer number, such that DMA1 stream0 equals 0, DMA2 stream0 equals 8,
* DMA2 stream 7 equals 15 and so on.
*
* @param[in] stream physical DMA stream
*/
static inline DMA_TypeDef *dma_base(int stream)
{
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
return (stream < 8) ? DMA1 : DMA2;
#elif defined(DMA2)
return (stream < 7) ? DMA1 : DMA2;
#else
(void)stream;
return DMA1;
#endif
}
#ifdef CPU_FAM_STM32F0
static inline DMA_TypeDef *dma_req(int stream_n)
{
return dma_base(stream_n);
}
#elif CPU_FAM_STM32L0 || CPU_FAM_STM32L4
static inline DMA_Request_TypeDef *dma_req(int stream_n)
{
#ifdef DMA2
return (stream_n < 7) ? DMA1_CSELR : DMA2_CSELR;
#else
(void)stream_n;
return DMA1_CSELR;
#endif
}
#endif
/**
* @brief Get the DMA stream base address
*
* @param[in] stream physical DMA stream
*
* @return base address for the selected DMA stream
*/
static inline STM32_DMA_Stream_Type *dma_stream(int stream)
{
uint32_t base = (uint32_t)dma_base(stream);
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
return (DMA_Stream_TypeDef *)(base + (0x10 + (0x18 * (stream & 0x7))));
#else
return (DMA_Channel_TypeDef *)(base + (0x08 + (0x14 * (stream & 0x7))));
#endif
}
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
/**
* @brief Select high or low DMA interrupt register based on stream number
*
* @param[in] stream physical DMA stream
*
* @return 0 for streams 0-3, 1 for streams 3-7
*/
static inline int dma_hl(int stream)
{
return ((stream & 0x4) >> 2);
}
#endif
static IRQn_Type dma_get_irqn(int stream)
{
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
if (stream < 7) {
return ((IRQn_Type)((int)DMA1_Stream0_IRQn + stream));
}
else if (stream == 7) {
return DMA1_Stream7_IRQn;
}
else if (stream < 13) {
return ((IRQn_Type)((int)DMA2_Stream0_IRQn + (stream - 8)));
}
else if (stream < 16) {
return ((IRQn_Type)((int)DMA2_Stream5_IRQn + (stream - 13)));
}
#elif CPU_FAM_STM32F0 || CPU_FAM_STM32L0
if (stream == 0) {
return (DMA1_Channel1_IRQn);
}
else if (stream < 3 || (stream >= 8 && stream < 11)) {
return (DMA1_Channel2_3_IRQn);
}
else if (stream < 7 || stream >= 11) {
return (DMA1_Channel4_5_6_7_IRQn);
}
#else
if (stream < 7) {
return ((IRQn_Type)((int)DMA1_Channel1_IRQn + stream));
}
#if defined(CPU_FAM_STM32F1)
else if (stream < 11) {
#else
else if (stream < 13 ) {
#endif
return ((IRQn_Type)((int)DMA2_Channel1_IRQn + stream));
}
#if !defined(CPU_FAM_STM32L1)
else {
#if defined(CPU_FAM_STM32F1)
return (DMA2_Channel4_5_IRQn);
#else
return ((IRQn_Type)((int)DMA2_Channel6_IRQn + stream));
#endif
}
#endif
#endif
return -1;
}
/**
* @brief Disable the interrupt of a given stream
*
* @param[in] stream physical DMA stream
*/
static inline void dma_isr_disable(int stream)
{
NVIC_DisableIRQ(dma_get_irqn(stream));
}
/**
* @brief Clear the interrupt of a given stream
*
* @param[in] stream physical DMA stream
*/
static inline void dma_isr_clear(int stream)
{
NVIC_ClearPendingIRQ(dma_get_irqn(stream));
}
/**
* @brief Enable the interrupt of a given stream
*
* @param[in] stream physical DMA stream
*/
static inline void dma_isr_enable(int stream)
{
NVIC_EnableIRQ(dma_get_irqn(stream));
}
static inline uint32_t dma_all_flags(dma_t dma)
{
assert(dma < DMA_NUMOF);
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
switch (dma_config[dma].stream & 0x3) {
case 0: /* 0 and 4 */
return (DMA_STREAM_IT_MASK);
case 1: /* 1 and 5 */
return (DMA_STREAM_IT_MASK << 6);
case 2: /* 2 and 6 */
return (DMA_STREAM_IT_MASK << 16);
case 3: /* 3 and 7 */
return (DMA_STREAM_IT_MASK << 22);
default:
return 0;
}
#else
return DMA_STREAM_IT_MASK << ((dma_config[dma].stream & 0x7) * 4);
#endif
}
static void dma_clear_all_flags(dma_t dma)
{
assert(dma < DMA_NUMOF);
DMA_TypeDef *dma_dev = dma_base(dma_config[dma].stream);
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
/* Clear all flags */
if (dma_hl(dma_config[dma].stream) == 0) {
dma_dev->LIFCR = dma_all_flags(dma);
}
else {
dma_dev->HIFCR = dma_all_flags(dma);
}
#else
dma_dev->IFCR = dma_all_flags(dma);
#endif
}
void dma_init(void)
{
for (unsigned i = 0; i < DMA_NUMOF; i++) {
mutex_init(&dma_ctx[i].conf_lock);
mutex_init(&dma_ctx[i].sync_lock);
mutex_lock(&dma_ctx[i].sync_lock);
}
}
static void dma_poweron(int stream)
{
if (stream < 8) {
periph_clk_en(CLOCK, RCC_MASK_DMA1);
}
#if defined(DMA2)
else {
periph_clk_en(CLOCK, RCC_MASK_DMA2);
}
#endif
}
int dma_transfer(dma_t dma, int chan, const volatile void *src, volatile void *dst, size_t len,
dma_mode_t mode, uint8_t flags)
{
int ret = dma_configure(dma, chan, src, dst, len, mode, flags);
if (ret != 0) {
return ret;
}
dma_start(dma);
dma_wait(dma);
dma_stop(dma);
return len;
}
void dma_acquire(dma_t dma)
{
assert(dma < DMA_NUMOF);
mutex_lock(&dma_ctx[dma].conf_lock);
#ifdef STM32_PM_STOP
/* block STOP mode */
pm_block(STM32_PM_STOP);
#endif
}
void dma_release(dma_t dma)
{
assert(dma < DMA_NUMOF);
#ifdef STM32_PM_STOP
/* unblock STOP mode */
pm_unblock(STM32_PM_STOP);
#endif
mutex_unlock(&dma_ctx[dma].conf_lock);
}
int dma_configure(dma_t dma, int chan, const volatile void *src, volatile void *dst, size_t len,
dma_mode_t mode, uint8_t flags)
{
assert(src != NULL);
assert(dst != NULL);
assert(dma < DMA_NUMOF);
int stream_n = dma_config[dma].stream;
uint32_t inc_periph;
uint32_t inc_mem;
STM32_DMA_Stream_Type *stream = dma_stream(stream_n);
dma_poweron(stream_n);
dma_clear_all_flags(dma);
switch (mode) {
case DMA_MEM_TO_MEM:
case DMA_PERIPH_TO_MEM:
stream->PERIPH_ADDR = (uint32_t)src;
stream->MEM_ADDR = (uint32_t)dst;
inc_periph = (flags & DMA_INC_SRC_ADDR);
inc_mem = (flags & DMA_INC_DST_ADDR) >> 1;
break;
case DMA_MEM_TO_PERIPH:
stream->PERIPH_ADDR = (uint32_t)dst;
stream->MEM_ADDR = (uint32_t)src;
inc_periph = (flags & DMA_INC_DST_ADDR) >> 1;
inc_mem = (flags & DMA_INC_SRC_ADDR);
break;
default:
return -1;
}
uint32_t width = (flags & DMA_DATA_WIDTH_MASK) >> DMA_DATA_WIDTH_SHIFT;
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
/* Set channel, data width, inc and mode */
stream->CR = (chan & 0xF) << DMA_SxCR_CHSEL_Pos |
width << DMA_SxCR_MSIZE_Pos | width << DMA_SxCR_PSIZE_Pos |
inc_periph << DMA_SxCR_PINC_Pos | inc_mem << DMA_SxCR_MINC_Pos |
(mode & 3) << DMA_SxCR_DIR_Pos;
/* Enable interrupts */
stream->CR |= DMA_SxCR_TCIE | DMA_SxCR_TEIE;
/* Configure FIFO */
stream->FCR = 0;
#else
#if defined(DMA_CSELR_C1S) || defined(DMA1_CSELR_DEFAULT)
dma_req(stream_n)->CSELR &= ~((0xF) << ((stream_n & 0x7) << 2));
dma_req(stream_n)->CSELR |= (chan & 0xF) << ((stream_n & 0x7) << 2);
#else
(void)chan;
#endif
stream->CONTROL_REG = width << DMA_CCR_MSIZE_Pos | width << DMA_CCR_PSIZE_Pos |
inc_periph << DMA_CCR_PINC_Pos | inc_mem << DMA_CCR_MINC_Pos |
(mode & 1) << DMA_CCR_DIR_Pos | ((mode & 2) >> 1) << DMA_CCR_MEM2MEM_Pos;
stream->CONTROL_REG |= DMA_CCR_TCIE | DMA_CCR_TEIE;
#endif
/* Set length */
stream->NDTR_REG = len;
dma_ctx[dma].len = len;
dma_isr_enable(stream_n);
return 0;
}
void dma_start(dma_t dma)
{
assert(dma < DMA_NUMOF);
STM32_DMA_Stream_Type *stream = dma_stream(dma_config[dma].stream);
stream->CONTROL_REG |= DMA_EN;
}
uint16_t dma_suspend(dma_t dma)
{
assert(dma < DMA_NUMOF);
int stream_n = dma_config[dma].stream;
STM32_DMA_Stream_Type *stream = dma_stream(stream_n);
uint16_t left = 0;
if ((stream->CONTROL_REG & DMA_EN) == DMA_EN) {
dma_isr_disable(stream_n);
stream->CONTROL_REG &= ~(uint32_t)DMA_EN;
while ((stream->CONTROL_REG & DMA_EN) == DMA_EN) {}
dma_clear_all_flags(dma);
left = stream->NDTR_REG;
dma_isr_clear(stream_n);
}
return left;
}
void dma_resume(dma_t dma, uint16_t remaining)
{
assert(dma < DMA_NUMOF);
int stream_n = dma_config[dma].stream;
STM32_DMA_Stream_Type *stream = dma_stream(stream_n);
if (remaining > 0) {
dma_isr_enable(stream_n);
stream->NDTR_REG = remaining;
stream->MEM_ADDR += dma_ctx[dma].len - remaining;
dma_ctx[dma].len = remaining;
stream->CONTROL_REG |= DMA_EN;
}
}
void dma_stop(dma_t dma)
{
assert(dma < DMA_NUMOF);
STM32_DMA_Stream_Type *stream = dma_stream(dma_config[dma].stream);
stream->CONTROL_REG &= ~(uint32_t)DMA_EN;
}
void dma_wait(dma_t dma)
{
assert(dma < DMA_NUMOF);
mutex_lock(&dma_ctx[dma].sync_lock);
}
void dma_isr_handler(dma_t dma)
{
dma_clear_all_flags(dma);
mutex_unlock(&dma_ctx[dma].sync_lock);
cortexm_isr_end();
}
#ifdef DMA_0_ISR
void DMA_0_ISR(void)
{
dma_isr_handler(0);
}
#endif
#ifdef DMA_1_ISR
void DMA_1_ISR(void)
{
dma_isr_handler(1);
}
#endif
#ifdef DMA_2_ISR
void DMA_2_ISR(void)
{
dma_isr_handler(2);
}
#endif
#ifdef DMA_3_ISR
void DMA_3_ISR(void)
{
dma_isr_handler(3);
}
#endif
#ifdef DMA_4_ISR
void DMA_4_ISR(void)
{
dma_isr_handler(4);
}
#endif
#ifdef DMA_5_ISR
void DMA_5_ISR(void)
{
dma_isr_handler(5);
}
#endif
#ifdef DMA_6_ISR
void DMA_6_ISR(void)
{
dma_isr_handler(6);
}
#endif
#ifdef DMA_7_ISR
void DMA_7_ISR(void)
{
dma_isr_handler(7);
}
#endif
#ifdef DMA_8_ISR
void DMA_8_ISR(void)
{
dma_isr_handler(8);
}
#endif
#ifdef DMA_9_ISR
void DMA_9_ISR(void)
{
dma_isr_handler(9);
}
#endif
#if defined(DMA_SHARED_ISR_0) || defined(DMA_SHARED_ISR_1)
static int dma_is_isr(dma_t dma)
{
DMA_TypeDef *dma_dev = dma_base(dma_config[dma].stream);
#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7
/* Clear all flags */
if (dma_hl(dma_config[dma].stream) == 0) {
return dma_dev->LISR & dma_all_flags(dma);
}
else {
return dma_dev->HISR & dma_all_flags(dma);
}
#else
return dma_dev->ISR & dma_all_flags(dma);
#endif
}
static void shared_isr(uint8_t *streams, size_t nb)
{
for (size_t i = 0; i < nb; i++) {
dma_t dma = streams[i];
if (dma_is_isr(dma)) {
dma_clear_all_flags(dma);
mutex_unlock(&dma_ctx[dma].sync_lock);
}
}
cortexm_isr_end();
}
#endif
#ifdef DMA_SHARED_ISR_0
void DMA_SHARED_ISR_0(void)
{
uint8_t streams[] = DMA_SHARED_ISR_0_STREAMS;
shared_isr(streams, ARRAY_SIZE(streams));
}
#endif
#ifdef DMA_SHARED_ISR_1
void DMA_SHARED_ISR_1(void)
{
uint8_t streams[] = DMA_SHARED_ISR_1_STREAMS;
shared_isr(streams, ARRAY_SIZE(streams));
}
#endif

View File

@ -1,120 +0,0 @@
/*
* Copyright (C) 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 cpu_stm32_common
* @ingroup drivers_periph_eeprom
* @{
*
* @file
* @brief Low-level eeprom driver implementation
*
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
* @author Oleg Artamonov <oleg@unwds.com>
* @author Francisco Molina <francois-xavier.molina@inria.fr>
*
* @}
*/
#include <assert.h>
#include "cpu.h"
#include "periph/eeprom.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
extern void _lock(void);
extern void _unlock(void);
extern void _wait_for_pending_operations(void);
#ifndef EEPROM_START_ADDR
#error "periph/eeprom: EEPROM_START_ADDR is not defined"
#endif
#if defined(CPU_MODEL_STM32L151CB)
#define ALIGN_MASK (0x00000003)
#define BYTE_MASK (0xFF)
#define BYTE_BITS (0x08)
static void _erase_word(uint32_t addr)
{
/* Wait for last operation to be completed */
_wait_for_pending_operations();
/* Write "00000000h" to valid address in the data memory" */
*(__IO uint32_t *)addr = 0x00000000;
}
static void _write_word(uint32_t addr, uint32_t data)
{
/* Wait for last operation to be completed */
_wait_for_pending_operations();
*(__IO uint32_t *)addr = data;
}
#endif
static void _write_byte(uint32_t addr, uint8_t data)
{
/* Wait for last operation to be completed */
_wait_for_pending_operations();
#if defined(CPU_MODEL_STM32L151CB)
/* stm32l1xxx cat 1 can't write NULL bytes RefManual p79*/
uint32_t tmp = 0;
uint32_t data_mask = 0;
if (data != (uint8_t)0x00) {
*(__IO uint8_t *)addr = data;
}
else {
tmp = *(__IO uint32_t *)(addr & (~ALIGN_MASK));
data_mask = BYTE_MASK << ((uint32_t)(BYTE_BITS * (addr & ALIGN_MASK)));
tmp &= ~data_mask;
_erase_word(addr & (~ALIGN_MASK));
_write_word((addr & (~ALIGN_MASK)), tmp);
}
#else
*(__IO uint8_t *)addr = data;
#endif
}
size_t eeprom_read(uint32_t pos, void *data, size_t len)
{
assert(pos + len <= EEPROM_SIZE);
uint8_t *p = data;
DEBUG("Reading data from EEPROM at pos %" PRIu32 ": ", pos);
for (size_t i = 0; i < len; i++) {
_wait_for_pending_operations();
*p++ = *(__IO uint8_t *)(EEPROM_START_ADDR + pos++);
DEBUG("0x%02X ", *p);
}
DEBUG("\n");
return len;
}
size_t eeprom_write(uint32_t pos, const void *data, size_t len)
{
assert(pos + len <= EEPROM_SIZE);
uint8_t *p = (uint8_t *)data;
_unlock();
for (size_t i = 0; i < len; i++) {
_write_byte((EEPROM_START_ADDR + pos++), *p++);
}
_lock();
return len;
}

View File

@ -1,360 +0,0 @@
/*
* Copyright (C) 2016 TriaGnoSys GmbH
*
* 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 cpu_stm32_common
* @{
*
* @file
* @brief Low-level ETH driver implementation
*
* @author Víctor Ariño <victor.arino@triagnosys.com>
*
* @}
*/
#include <string.h>
#include "mutex.h"
#include "luid.h"
#include "iolist.h"
#include "net/ethernet.h"
#include "periph/gpio.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/* Set the value of the divider with the clock configured */
#if !defined(CLOCK_CORECLOCK) || CLOCK_CORECLOCK < (20000000U)
#error This peripheral requires a CORECLOCK of at least 20MHz
#elif CLOCK_CORECLOCK < (35000000U)
#define CLOCK_RANGE ETH_MACMIIAR_CR_Div16
#elif CLOCK_CORECLOCK < (60000000U)
#define CLOCK_RANGE ETH_MACMIIAR_CR_Div26
#elif CLOCK_CORECLOCK < (100000000U)
#define CLOCK_RANGE ETH_MACMIIAR_CR_Div42
#elif CLOCK_CORECLOCK < (150000000U)
#define CLOCK_RANGE ETH_MACMIIAR_CR_Div62
#else /* CLOCK_CORECLOCK < (20000000U) */
#define CLOCK_RANGE ETH_MACMIIAR_CR_Div102
#endif /* CLOCK_CORECLOCK < (20000000U) */
/* Internal flags for the DMA descriptors */
#define DESC_OWN (0x80000000)
#define RX_DESC_FL (0x3FFF0000)
#define RX_DESC_FS (0x00000200)
#define RX_DESC_LS (0x00000100)
#define RX_DESC_RCH (0x00004000)
#define TX_DESC_TCH (0x00100000)
#define TX_DESC_IC (0x40000000)
#define TX_DESC_CIC (0x00C00000)
#define TX_DESC_LS (0x20000000)
#define TX_DESC_FS (0x10000000)
struct eth_dma_desc {
uint32_t status;
uint32_t control;
char *buffer_addr;
struct eth_dma_desc *desc_next;
uint32_t reserved1_ext;
uint32_t reserved2;
uint32_t ts_low;
uint32_t ts_high;
} __attribute__((packed));
typedef struct eth_dma_desc edma_desc_t;
/* Descriptors */
static edma_desc_t rx_desc[ETH_RX_BUFFER_COUNT];
static edma_desc_t tx_desc[ETH_TX_BUFFER_COUNT];
static edma_desc_t *rx_curr;
static edma_desc_t *tx_curr;
/* Buffers */
static char rx_buffer[ETH_RX_BUFFER_COUNT][ETH_RX_BUFFER_SIZE];
static char tx_buffer[ETH_TX_BUFFER_COUNT][ETH_TX_BUFFER_SIZE];
/** Read or write a phy register, to write the register ETH_MACMIIAR_MW is to
* be passed as the higher nibble of the value */
static unsigned _rw_phy(unsigned addr, unsigned reg, unsigned value)
{
unsigned tmp;
while (ETH->MACMIIAR & ETH_MACMIIAR_MB) {}
DEBUG("stm32_eth: rw_phy %x (%x): %x\n", addr, reg, value);
tmp = (ETH->MACMIIAR & ETH_MACMIIAR_CR) | ETH_MACMIIAR_MB;
tmp |= (((addr & 0x1f) << 11) | ((reg & 0x1f) << 6));
tmp |= (value >> 16);
ETH->MACMIIDR = (value & 0xffff);
ETH->MACMIIAR = tmp;
while (ETH->MACMIIAR & ETH_MACMIIAR_MB) {}
DEBUG("stm32_eth: %lx\n", ETH->MACMIIDR);
return (ETH->MACMIIDR & 0x0000ffff);
}
int32_t stm32_eth_phy_read(uint16_t addr, uint8_t reg)
{
return _rw_phy(addr, reg, 0);
}
int32_t stm32_eth_phy_write(uint16_t addr, uint8_t reg, uint16_t value)
{
_rw_phy(addr, reg, (value & 0xffff) | (ETH_MACMIIAR_MW << 16));
return 0;
}
void stm32_eth_get_mac(char *out)
{
unsigned t;
t = ETH->MACA0HR;
out[5] = (t >> 8);
out[4] = (t & 0xff);
t = ETH->MACA0LR;
out[3] = (t >> 24);
out[2] = (t >> 16);
out[1] = (t >> 8);
out[0] = (t & 0xff);
}
/** Set the mac address. The peripheral supports up to 4 MACs but only one is
* implemented */
void stm32_eth_set_mac(const char *mac)
{
ETH->MACA0HR &= 0xffff0000;
ETH->MACA0HR |= ((mac[5] << 8) | mac[4]);
ETH->MACA0LR = ((mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0]);
}
/** Initialization of the DMA descriptors to be used */
static void _init_buffer(void)
{
int i;
for (i = 0; i < ETH_RX_BUFFER_COUNT; i++) {
rx_desc[i].status = DESC_OWN;
rx_desc[i].control = RX_DESC_RCH | (ETH_RX_BUFFER_SIZE & 0x0fff);
rx_desc[i].buffer_addr = &rx_buffer[i][0];
if((i+1) < ETH_RX_BUFFER_COUNT) {
rx_desc[i].desc_next = &rx_desc[i + 1];
}
}
rx_desc[i - 1].desc_next = &rx_desc[0];
for (i = 0; i < ETH_TX_BUFFER_COUNT; i++) {
tx_desc[i].status = TX_DESC_TCH | TX_DESC_CIC;
tx_desc[i].buffer_addr = &tx_buffer[i][0];
if ((i + 1) < ETH_RX_BUFFER_COUNT) {
tx_desc[i].desc_next = &tx_desc[i + 1];
}
}
tx_desc[i - 1].desc_next = &tx_desc[0];
rx_curr = &rx_desc[0];
tx_curr = &tx_desc[0];
ETH->DMARDLAR = (uint32_t)rx_curr;
ETH->DMATDLAR = (uint32_t)tx_curr;
}
int stm32_eth_init(void)
{
/* enable APB2 clock */
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
/* select RMII if necessary */
if (eth_config.mode == RMII) {
SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL;
}
/* initialize GPIO */
for (int i = 0; i < (int) eth_config.mode; i++) {
gpio_init(eth_config.pins[i], GPIO_OUT);
gpio_init_af(eth_config.pins[i], GPIO_AF11);
}
/* enable all clocks */
RCC->AHB1ENR |= (RCC_AHB1ENR_ETHMACEN | RCC_AHB1ENR_ETHMACTXEN |
RCC_AHB1ENR_ETHMACRXEN | RCC_AHB1ENR_ETHMACPTPEN);
/* reset the peripheral */
RCC->AHB1RSTR |= RCC_AHB1RSTR_ETHMACRST;
RCC->AHB1RSTR &= ~RCC_AHB1RSTR_ETHMACRST;
/* software reset */
ETH->DMABMR |= ETH_DMABMR_SR;
while (ETH->DMABMR & ETH_DMABMR_SR) {}
/* set the clock divider */
while (ETH->MACMIIAR & ETH_MACMIIAR_MB) {}
ETH->MACMIIAR = CLOCK_RANGE;
/* configure the PHY (standard for all PHY's) */
/* if there's no PHY, this has no effect */
stm32_eth_phy_write(eth_config.phy_addr, PHY_BMCR, BMCR_RESET);
/* speed from conf */
ETH->MACCR |= (ETH_MACCR_ROD | ETH_MACCR_IPCO | ETH_MACCR_APCS |
((eth_config.speed & 0x0100) << 3) |
((eth_config.speed & 0x2000) << 1));
/* pass all */
//ETH->MACFFR |= ETH_MACFFR_RA;
/* pass on perfect filter match and pass all multicast address matches */
ETH->MACFFR |= ETH_MACFFR_PAM;
/* store forward */
ETH->DMAOMR |= (ETH_DMAOMR_RSF | ETH_DMAOMR_TSF | ETH_DMAOMR_OSF);
/* configure DMA */
ETH->DMABMR = (ETH_DMABMR_DA | ETH_DMABMR_AAB | ETH_DMABMR_FB |
ETH_DMABMR_RDP_32Beat | ETH_DMABMR_PBL_32Beat | ETH_DMABMR_EDE);
if(eth_config.mac[0] != 0) {
stm32_eth_set_mac(eth_config.mac);
}
else {
eui48_t hwaddr;
luid_get_eui48(&hwaddr);
stm32_eth_set_mac((const char *)hwaddr.uint8);
}
_init_buffer();
NVIC_EnableIRQ(ETH_IRQn);
ETH->DMAIER |= ETH_DMAIER_NISE | ETH_DMAIER_TIE | ETH_DMAIER_RIE;
/* enable */
ETH->MACCR |= ETH_MACCR_TE;
ETH->DMAOMR |= ETH_DMAOMR_FTF;
ETH->MACCR |= ETH_MACCR_RE;
ETH->DMAOMR |= ETH_DMAOMR_ST;
ETH->DMAOMR |= ETH_DMAOMR_SR;
/* configure speed, do it at the end so the PHY had time to
* reset */
stm32_eth_phy_write(eth_config.phy_addr, PHY_BMCR, eth_config.speed);
return 0;
}
int stm32_eth_send(const struct iolist *iolist)
{
unsigned len = iolist_size(iolist);
int ret = 0;
/* safety check */
if (len > ETH_TX_BUFFER_SIZE) {
DEBUG("stm32_eth: Error iolist_size > ETH_TX_BUFFER_SIZE\n");
return -1;
}
/* block until there's an available descriptor */
while (tx_curr->status & DESC_OWN) {
DEBUG("stm32_eth: not avail\n");
}
/* clear status field */
tx_curr->status &= 0x0fffffff;
dma_acquire(eth_config.dma);
for (; iolist; iolist = iolist->iol_next) {
ret += dma_transfer(eth_config.dma, eth_config.dma_chan, iolist->iol_base,
tx_curr->buffer_addr+ret, iolist->iol_len, DMA_MEM_TO_MEM, DMA_INC_BOTH_ADDR);
}
dma_release(eth_config.dma);
if (ret < 0) {
DEBUG("stm32_eth: Failure in dma_transfer\n");
return ret;
}
tx_curr->control = (len & 0x1fff);
/* set flags for first and last frames */
tx_curr->status |= TX_DESC_FS;
tx_curr->status |= TX_DESC_LS | TX_DESC_IC;
/* give the descriptors to the DMA */
tx_curr->status |= DESC_OWN;
tx_curr = tx_curr->desc_next;
/* start tx */
ETH->DMATPDR = 0;
return ret;
}
static int _try_receive(char *data, int max_len, int block)
{
int copy, len = 0;
int copied = 0;
int drop = (data || max_len > 0);
edma_desc_t *p = rx_curr;
for (int i = 0; i < ETH_RX_BUFFER_COUNT && len == 0; i++) {
/* try receiving, if the block is set, simply wait for the rest of
* the packet to complete, otherwise just break */
while (p->status & DESC_OWN) {
if (!block) {
break;
}
}
/* amount of data to copy */
copy = ETH_RX_BUFFER_SIZE;
if (p->status & (RX_DESC_LS | RX_DESC_FL)) {
len = ((p->status >> 16) & 0x3FFF) - 4;
copy = len - copied;
}
if (drop) {
/* copy the data if possible */
if (data && max_len >= copy) {
memcpy(data, p->buffer_addr, copy);
max_len -= copy;
}
else if (max_len < copy) {
len = -1;
}
p->status = DESC_OWN;
}
p = p->desc_next;
}
if (drop) {
rx_curr = p;
}
return len;
}
int stm32_eth_try_receive(char *data, unsigned max_len)
{
return _try_receive(data, max_len, 0);
}
int stm32_eth_receive_blocking(char *data, unsigned max_len)
{
return _try_receive(data, max_len, 1);
}
int stm32_eth_get_rx_status_owned(void)
{
return (!(rx_curr->status & DESC_OWN));
}
void stm32_eth_isr_eth_wkup(void)
{
cortexm_isr_end();
}

View File

@ -1,75 +0,0 @@
/*
* Copyright (C) 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 cpu_stm32_common
* @{
*
* @file
* @brief Low-level flash lock/unlock implementation
*
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
* @author Oleg Artamonov <oleg@unwds.com>
*
* @}
*/
#include "cpu.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
/* Data EEPROM and control register unlock keys */
#define FLASH_KEY1 ((uint32_t)0x89ABCDEF)
#define FLASH_KEY2 ((uint32_t)0x02030405)
#define CNTRL_REG (FLASH->PECR)
#define CNTRL_REG_LOCK (FLASH_PECR_PELOCK)
#define KEY_REG (FLASH->PEKEYR)
#else
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
#define FLASH_KEY1 ((uint32_t)0x45670123)
#define FLASH_KEY2 ((uint32_t)0xCDEF89AB)
#endif
#define CNTRL_REG (FLASH->CR)
#define CNTRL_REG_LOCK (FLASH_CR_LOCK)
#define KEY_REG (FLASH->KEYR)
#endif
void _unlock(void)
{
if (CNTRL_REG & CNTRL_REG_LOCK) {
DEBUG("[flash-common] unlocking the flash module\n");
KEY_REG = FLASH_KEY1;
KEY_REG = FLASH_KEY2;
}
}
void _lock(void)
{
if (!(CNTRL_REG & CNTRL_REG_LOCK)) {
DEBUG("[flash-common] locking the flash module\n");
CNTRL_REG |= CNTRL_REG_LOCK;
}
}
void _wait_for_pending_operations(void)
{
if (FLASH->SR & FLASH_SR_BSY) {
DEBUG("[flash-common] waiting for any pending operation to finish\n");
while (FLASH->SR & FLASH_SR_BSY) {}
}
/* Clear 'end of operation' bit in status register, for other STM32 boards
this bit is set only if EOPIE is set, which is currently not done */
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L0) || \
defined(CPU_FAM_STM32L1)
FLASH->SR |= FLASH_SR_EOP;
#endif
}

View File

@ -1,242 +0,0 @@
/*
* Copyright (C) 2016 Freie Universität Berlin
* 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 cpu_stm32_common
* @ingroup drivers_periph_flashpage
* @{
*
* @file
* @brief Low-level flash page driver implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Francisco Acosta <francisco.acosta@inria.fr>
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
*
* @}
*/
#include "cpu.h"
#include "stmclk.h"
#include "assert.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "periph/flashpage.h"
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
/* Program memory unlock keys */
#define FLASH_PRGKEY1 ((uint32_t)0x8C9DAEBF)
#define FLASH_PRGKEY2 ((uint32_t)0x13141516)
#define CNTRL_REG (FLASH->PECR)
#define CNTRL_REG_LOCK (FLASH_PECR_PELOCK)
#define FLASH_CR_PER (FLASH_PECR_ERASE | FLASH_PECR_PROG)
#define FLASHPAGE_DIV (4U) /* write 4 bytes in one go */
#else
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
#define FLASHPAGE_DIV (8U)
#else
#define FLASHPAGE_DIV (2U)
#endif
#define CNTRL_REG (FLASH->CR)
#define CNTRL_REG_LOCK (FLASH_CR_LOCK)
#endif
extern void _lock(void);
extern void _unlock(void);
extern void _wait_for_pending_operations(void);
static void _unlock_flash(void)
{
_unlock();
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
DEBUG("[flashpage] unlocking the flash program memory\n");
if (!(CNTRL_REG & CNTRL_REG_LOCK)) {
if (CNTRL_REG & FLASH_PECR_PRGLOCK) {
DEBUG("[flashpage] setting the program memory unlock keys\n");
FLASH->PRGKEYR = FLASH_PRGKEY1;
FLASH->PRGKEYR = FLASH_PRGKEY2;
}
}
#endif
}
static void _erase_page(void *page_addr)
{
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) || \
defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
uint32_t *dst = page_addr;
#else
uint16_t *dst = page_addr;
#endif
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F3)
uint32_t hsi_state = (RCC->CR & RCC_CR_HSION);
/* the internal RC oscillator (HSI) must be enabled */
stmclk_enable_hsi();
#endif
/* unlock the flash module */
_unlock_flash();
/* make sure no flash operation is ongoing */
_wait_for_pending_operations();
/* set page erase bit and program page address */
DEBUG("[flashpage] erase: setting the erase bit\n");
CNTRL_REG |= FLASH_CR_PER;
DEBUG("address to erase: %p\n", page_addr);
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
DEBUG("[flashpage] erase: trigger the page erase\n");
*dst = (uint32_t)0;
#elif defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
DEBUG("[flashpage] erase: setting the page address\n");
uint8_t pn;
#if (FLASHPAGE_NUMOF <= 256) || defined(CPU_FAM_STM32WB)
pn = (uint8_t)flashpage_page(dst);
#else
uint16_t page = flashpage_page(dst);
if (page > 255) {
CNTRL_REG |= FLASH_CR_BKER;
}
else {
CNTRL_REG &= ~FLASH_CR_BKER;
}
pn = (uint8_t)page;
#endif
CNTRL_REG &= ~FLASH_CR_PNB;
CNTRL_REG |= (uint32_t)(pn << FLASH_CR_PNB_Pos);
CNTRL_REG |= FLASH_CR_STRT;
#else /* CPU_FAM_STM32F0 || CPU_FAM_STM32F1 || CPU_FAM_STM32F3 */
DEBUG("[flashpage] erase: setting the page address\n");
FLASH->AR = (uint32_t)dst;
/* trigger the page erase and wait for it to be finished */
DEBUG("[flashpage] erase: trigger the page erase\n");
CNTRL_REG |= FLASH_CR_STRT;
#endif
/* wait as long as device is busy */
_wait_for_pending_operations();
/* reset PER bit */
DEBUG("[flashpage] erase: resetting the page erase bit\n");
CNTRL_REG &= ~(FLASH_CR_PER);
/* lock the flash module again */
_lock();
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F3)
/* restore the HSI state */
if (!hsi_state) {
stmclk_disable_hsi();
}
#endif
}
void flashpage_write_raw(void *target_addr, const void *data, size_t len)
{
/* assert multiples of FLASHPAGE_RAW_BLOCKSIZE are written and no less of
that length. */
assert(!(len % FLASHPAGE_RAW_BLOCKSIZE));
/* ensure writes are aligned */
assert(!(((unsigned)target_addr % FLASHPAGE_RAW_ALIGNMENT) ||
((unsigned)data % FLASHPAGE_RAW_ALIGNMENT)));
/* ensure the length doesn't exceed the actual flash size */
assert(((unsigned)target_addr + len) <
(CPU_FLASH_BASE + (FLASHPAGE_SIZE * FLASHPAGE_NUMOF)) + 1);
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
uint32_t *dst = target_addr;
const uint32_t *data_addr = data;
#elif defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
uint64_t *dst = target_addr;
const uint64_t *data_addr = data;
#else
uint16_t *dst = (uint16_t *)target_addr;
const uint16_t *data_addr = data;
#endif
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F3)
uint32_t hsi_state = (RCC->CR & RCC_CR_HSION);
/* the internal RC oscillator (HSI) must be enabled */
stmclk_enable_hsi();
#endif
/* unlock the flash module */
_unlock_flash();
/* make sure no flash operation is ongoing */
_wait_for_pending_operations();
DEBUG("[flashpage_raw] write: now writing the data\n");
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4) || \
defined(CPU_FAM_STM32WB)
/* set PG bit and program page to flash */
CNTRL_REG |= FLASH_CR_PG;
#endif
for (size_t i = 0; i < (len / FLASHPAGE_DIV); i++) {
DEBUG("[flashpage_raw] writing %c to %p\n", (char)data_addr[i], dst);
*dst++ = data_addr[i];
/* wait as long as device is busy */
_wait_for_pending_operations();
}
/* clear program bit again */
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4) || \
defined(CPU_FAM_STM32WB)
CNTRL_REG &= ~(FLASH_CR_PG);
#endif
DEBUG("[flashpage_raw] write: done writing data\n");
/* lock the flash module again */
_lock();
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F3)
/* restore the HSI state */
if (!hsi_state) {
stmclk_disable_hsi();
}
#endif
}
void flashpage_write(int page, const void *data)
{
assert(page < (int)FLASHPAGE_NUMOF);
/* ensure there is no attempt to write to CPU2 protected area */
#if defined(CPU_FAM_STM32WB)
assert(page < (int)(FLASH->SFR & FLASH_SFR_SFSA));
#endif
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
/* STM32L0/L1 only supports word sizes */
uint32_t *page_addr = flashpage_addr(page);
#elif defined(CPU_FAM_STM32L4)
uint64_t *page_addr = flashpage_addr(page);
#else
/* Default is to support half-word sizes */
uint16_t *page_addr = flashpage_addr(page);
#endif
/* ERASE sequence */
_erase_page(page_addr);
/* WRITE sequence */
if (data != NULL) {
flashpage_write_raw(page_addr, data, FLASHPAGE_SIZE);
}
}

View File

@ -1,264 +0,0 @@
/*
* Copyright (C) 2014-2015 Freie Universität Berlin
* 2015 Hamburg University of Applied Sciences
* 2017 Inria
* 2017 OTA keys S.A.
*
* 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 cpu_stm32_common
* @ingroup drivers_periph_gpio
* @{
*
* @file
* @brief Low-level GPIO driver implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Fabian Nack <nack@inf.fu-berlin.de>
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
* @author Katja Kirstein <katja.kirstein@haw-hamburg.de>
* @author Vincent Dupont <vincent@otakeys.com>
*
* @}
*/
#include "cpu.h"
#include "periph/gpio.h"
#include "periph_conf.h"
/* this implementation is not valid for the stm32f1 */
#ifndef CPU_FAM_STM32F1
#ifdef MODULE_PERIPH_GPIO_IRQ
/**
* @brief The STM32F0 family has 16 external interrupt lines
*/
#define EXTI_NUMOF (16U)
/**
* @brief Allocate memory for one callback and argument per EXTI channel
*/
static gpio_isr_ctx_t isr_ctx[EXTI_NUMOF];
#endif /* MODULE_PERIPH_GPIO_IRQ */
/**
* @brief Extract the port base address from the given pin identifier
*/
static inline GPIO_TypeDef *_port(gpio_t pin)
{
return (GPIO_TypeDef *)(pin & ~(0x0f));
}
/**
* @brief Extract the port number form the given identifier
*
* The port number is extracted by looking at bits 10, 11, 12, 13 of the base
* register addresses.
*/
static inline int _port_num(gpio_t pin)
{
return ((pin >> 10) & 0x0f);
}
/**
* @brief Extract the pin number from the last 4 bit of the pin identifier
*/
static inline int _pin_num(gpio_t pin)
{
return (pin & 0x0f);
}
int gpio_init(gpio_t pin, gpio_mode_t mode)
{
GPIO_TypeDef *port = _port(pin);
int pin_num = _pin_num(pin);
/* enable clock */
#if defined(CPU_FAM_STM32F0) || defined (CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L1)
periph_clk_en(AHB, (RCC_AHBENR_GPIOAEN << _port_num(pin)));
#elif defined (CPU_FAM_STM32L0)
periph_clk_en(IOP, (RCC_IOPENR_GPIOAEN << _port_num(pin)));
#elif defined (CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
periph_clk_en(AHB2, (RCC_AHB2ENR_GPIOAEN << _port_num(pin)));
#ifdef PWR_CR2_IOSV
if (port == GPIOG) {
/* Port G requires external power supply */
periph_clk_en(APB1, RCC_APB1ENR1_PWREN);
PWR->CR2 |= PWR_CR2_IOSV;
}
#endif /* PWR_CR2_IOSV */
#else
periph_clk_en(AHB1, (RCC_AHB1ENR_GPIOAEN << _port_num(pin)));
#endif
/* set mode */
port->MODER &= ~(0x3 << (2 * pin_num));
port->MODER |= ((mode & 0x3) << (2 * pin_num));
/* set pull resistor configuration */
port->PUPDR &= ~(0x3 << (2 * pin_num));
port->PUPDR |= (((mode >> 2) & 0x3) << (2 * pin_num));
/* set output mode */
port->OTYPER &= ~(1 << pin_num);
port->OTYPER |= (((mode >> 4) & 0x1) << pin_num);
/* set pin speed to maximum */
port->OSPEEDR |= (3 << (2 * pin_num));
return 0;
}
void gpio_init_af(gpio_t pin, gpio_af_t af)
{
GPIO_TypeDef *port = _port(pin);
uint32_t pin_num = _pin_num(pin);
/* set pin to AF mode */
port->MODER &= ~(3 << (2 * pin_num));
port->MODER |= (2 << (2 * pin_num));
/* set selected function */
port->AFR[(pin_num > 7) ? 1 : 0] &= ~(0xf << ((pin_num & 0x07) * 4));
port->AFR[(pin_num > 7) ? 1 : 0] |= (af << ((pin_num & 0x07) * 4));
}
void gpio_init_analog(gpio_t pin)
{
/* enable clock, needed as this function can be used without calling
* gpio_init first */
#if defined(CPU_FAM_STM32F0) || defined (CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L1)
periph_clk_en(AHB, (RCC_AHBENR_GPIOAEN << _port_num(pin)));
#elif defined (CPU_FAM_STM32L0)
periph_clk_en(IOP, (RCC_IOPENR_GPIOAEN << _port_num(pin)));
#elif defined (CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
periph_clk_en(AHB2, (RCC_AHB2ENR_GPIOAEN << _port_num(pin)));
#else
periph_clk_en(AHB1, (RCC_AHB1ENR_GPIOAEN << _port_num(pin)));
#endif
/* set to analog mode */
_port(pin)->MODER |= (0x3 << (2 * _pin_num(pin)));
}
void gpio_irq_enable(gpio_t pin)
{
EXTI->IMR |= (1 << _pin_num(pin));
}
void gpio_irq_disable(gpio_t pin)
{
EXTI->IMR &= ~(1 << _pin_num(pin));
}
int gpio_read(gpio_t pin)
{
return (_port(pin)->IDR & (1 << _pin_num(pin)));
}
void gpio_set(gpio_t pin)
{
_port(pin)->BSRR = (1 << _pin_num(pin));
}
void gpio_clear(gpio_t pin)
{
_port(pin)->BSRR = (1 << (_pin_num(pin) + 16));
}
void gpio_toggle(gpio_t pin)
{
if (gpio_read(pin)) {
gpio_clear(pin);
} else {
gpio_set(pin);
}
}
void gpio_write(gpio_t pin, int value)
{
if (value) {
gpio_set(pin);
} else {
gpio_clear(pin);
}
}
#ifdef MODULE_PERIPH_GPIO_IRQ
int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
gpio_cb_t cb, void *arg)
{
int pin_num = _pin_num(pin);
int port_num = _port_num(pin);
/* set callback */
isr_ctx[pin_num].cb = cb;
isr_ctx[pin_num].arg = arg;
/* enable clock of the SYSCFG module for EXTI configuration */
#ifndef CPU_FAM_STM32WB
#ifdef CPU_FAM_STM32F0
periph_clk_en(APB2, RCC_APB2ENR_SYSCFGCOMPEN);
#else
periph_clk_en(APB2, RCC_APB2ENR_SYSCFGEN);
#endif
#endif
/* initialize pin as input */
gpio_init(pin, mode);
/* enable global pin interrupt */
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0)
if (pin_num < 2) {
NVIC_EnableIRQ(EXTI0_1_IRQn);
}
else if (pin_num < 4) {
NVIC_EnableIRQ(EXTI2_3_IRQn);
}
else {
NVIC_EnableIRQ(EXTI4_15_IRQn);
}
#else
if (pin_num < 5) {
NVIC_EnableIRQ(EXTI0_IRQn + pin_num);
}
else if (pin_num < 10) {
NVIC_EnableIRQ(EXTI9_5_IRQn);
}
else {
NVIC_EnableIRQ(EXTI15_10_IRQn);
}
#endif
/* configure the active flank */
EXTI->RTSR &= ~(1 << pin_num);
EXTI->RTSR |= ((flank & 0x1) << pin_num);
EXTI->FTSR &= ~(1 << pin_num);
EXTI->FTSR |= ((flank >> 1) << pin_num);
/* enable specific pin as exti sources */
SYSCFG->EXTICR[pin_num >> 2] &= ~(0xf << ((pin_num & 0x03) * 4));
SYSCFG->EXTICR[pin_num >> 2] |= (port_num << ((pin_num & 0x03) * 4));
/* clear any pending requests */
EXTI->PR = (1 << pin_num);
/* unmask the pins interrupt channel */
EXTI->IMR |= (1 << pin_num);
return 0;
}
void isr_exti(void)
{
/* only generate interrupts against lines which have their IMR set */
uint32_t pending_isr = (EXTI->PR & EXTI->IMR);
for (size_t i = 0; i < EXTI_NUMOF; i++) {
if (pending_isr & (1 << i)) {
EXTI->PR = (1 << i); /* clear by writing a 1 */
isr_ctx[i].cb(isr_ctx[i].arg);
}
}
cortexm_isr_end();
}
#endif /* MODULE_PERIPH_GPIO_IRQ */
#else
typedef int dont_be_pedantic;
#endif

View File

@ -1,79 +0,0 @@
/*
* Copyright (C) 2014-2017 Freie Universität Berlin
* 2016 OTA keys S.A.
*
* 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 cpu_stm32_common
* @ingroup drivers_periph_hwrng
* @{
*
* @file
* @brief Low-level random number generator driver implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Aurelien Gonce <aurelien.gonce@altran.fr>
*
* @}
*/
#include "cpu.h"
#include "periph_conf.h"
#include "periph/hwrng.h"
/* only build if the CPU actually provides a RNG peripheral */
#ifdef RNG
void hwrng_init(void)
{
/* no need for initialization */
}
void hwrng_read(void *buf, unsigned int num)
{
unsigned int count = 0;
uint8_t *b = (uint8_t *)buf;
/* power on and enable the device */
#if defined(CPU_LINE_STM32F410Rx)
periph_clk_en(AHB1, RCC_AHB1ENR_RNGEN);
#elif defined(CPU_FAM_STM32L0)
periph_clk_en(AHB, RCC_AHBENR_RNGEN);
#elif defined(CPU_FAM_STM32WB)
periph_clk_en(AHB3, RCC_AHB3ENR_RNGEN);
#else
periph_clk_en(AHB2, RCC_AHB2ENR_RNGEN);
#endif
RNG->CR = RNG_CR_RNGEN;
/* get random data */
while (count < num) {
/* wait for random data to be ready to read */
while (!(RNG->SR & RNG_SR_DRDY)) {}
/* read next 4 bytes */
uint32_t tmp = RNG->DR;
/* copy data into result vector */
for (int i = 0; i < 4 && count < num; i++) {
b[count++] = (uint8_t)tmp;
tmp = tmp >> 8;
}
}
/* finally disable the device again */
RNG->CR = 0;
#if defined(CPU_LINE_STM32F410Rx)
periph_clk_dis(AHB1, RCC_AHB1ENR_RNGEN);
#elif defined(CPU_FAM_STM32L0)
periph_clk_dis(AHB, RCC_AHBENR_RNGEN);
#elif defined(CPU_FAM_STM32WB)
periph_clk_dis(AHB3, RCC_AHB3ENR_RNGEN);
#else
periph_clk_dis(AHB2, RCC_AHB2ENR_RNGEN);
#endif
}
#endif /* RNG */

View File

@ -1,446 +0,0 @@
/*
* Copyright (C) 2015 Jan Pohlmann <jan-pohlmann@gmx.de>
* 2017 we-sens.com
* 2018 Inria
* 2018 HAW Hamburg
*
* 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 cpu_stm32_common
* @ingroup drivers_periph_i2c
* @{
*
* @file
* @brief Low-level I2C driver implementation
*
* This driver supports the STM32 F0, F3, F7, L0, L4 & WB families.
* @note This implementation only implements the 7-bit addressing polling mode
* (for now interrupt mode is not available)
*
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
* @author Jan Pohlmann <jan-pohlmann@gmx.de>
* @author Aurélien Fillau <aurelien.fillau@we-sens.com>
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
* @author Kevin Weiss <kevin.weiss@haw-hamburg.de>
*
* @}
*/
#include <assert.h>
#include <stdint.h>
#include <errno.h>
#include "cpu.h"
#include "mutex.h"
#include "byteorder.h"
#include "cpu_conf_stm32_common.h"
#include "periph/i2c.h"
#include "periph/gpio.h"
#include "periph_conf.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define TICK_TIMEOUT (0xFFFF)
#define MAX_BYTES_PER_FRAME (256)
#define I2C_IRQ_PRIO (1)
#define I2C_FLAG_READ (I2C_READ << I2C_CR2_RD_WRN_Pos)
#define I2C_FLAG_WRITE (0)
#define CLEAR_FLAG (I2C_ICR_NACKCF | I2C_ICR_ARLOCF | I2C_ICR_BERRCF | I2C_ICR_ADDRCF)
/* static function definitions */
static inline void _i2c_init(I2C_TypeDef *i2c, uint32_t timing);
static int _write(I2C_TypeDef *i2c, uint16_t addr, const void *data,
size_t length, uint8_t flags, uint32_t cr2_flags);
static int _start(I2C_TypeDef *i2c, uint32_t cr2, uint8_t flags);
static int _stop(I2C_TypeDef *i2c);
static int _wait_isr_set(I2C_TypeDef *i2c, uint32_t mask, uint8_t flags);
static inline int _wait_for_bus(I2C_TypeDef *i2c);
/**
* @brief Array holding one pre-initialized mutex for each I2C device
*/
static mutex_t locks[I2C_NUMOF];
void i2c_init(i2c_t dev)
{
assert(dev < I2C_NUMOF);
DEBUG("[i2c] init: initializing device\n");
mutex_init(&locks[dev]);
I2C_TypeDef *i2c = i2c_config[dev].dev;
periph_clk_en(i2c_config[dev].bus, i2c_config[dev].rcc_mask);
NVIC_SetPriority(i2c_config[dev].irqn, I2C_IRQ_PRIO);
NVIC_EnableIRQ(i2c_config[dev].irqn);
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3)
/* Set I2CSW bits to enable I2C clock source */
RCC->CFGR3 |= i2c_config[dev].rcc_sw_mask;
#endif
DEBUG("[i2c] init: configuring pins\n");
/* configure pins */
gpio_init(i2c_config[dev].scl_pin, GPIO_OD_PU);
gpio_init_af(i2c_config[dev].scl_pin, i2c_config[dev].scl_af);
gpio_init(i2c_config[dev].sda_pin, GPIO_OD_PU);
gpio_init_af(i2c_config[dev].sda_pin, i2c_config[dev].sda_af);
DEBUG("[i2c] init: configuring device\n");
/* set the timing register value from predefined values */
i2c_timing_param_t tp = timing_params[i2c_config[dev].speed];
uint32_t timing = (( (uint32_t)tp.presc << I2C_TIMINGR_PRESC_Pos) |
( (uint32_t)tp.scldel << I2C_TIMINGR_SCLDEL_Pos) |
( (uint32_t)tp.sdadel << I2C_TIMINGR_SDADEL_Pos) |
( (uint16_t)tp.sclh << I2C_TIMINGR_SCLH_Pos) |
tp.scll);
_i2c_init(i2c, timing);
}
static void _i2c_init(I2C_TypeDef *i2c, uint32_t timing)
{
assert(i2c != NULL);
/* disable device */
i2c->CR1 &= ~(I2C_CR1_PE);
/* configure analog noise filter */
i2c->CR1 |= I2C_CR1_ANFOFF;
/* configure digital noise filter */
i2c->CR1 |= I2C_CR1_DNF;
/* set timing registers */
i2c->TIMINGR = timing;
/* configure clock stretching */
i2c->CR1 &= ~(I2C_CR1_NOSTRETCH);
/* Clear interrupt */
i2c->ICR |= CLEAR_FLAG;
/* enable device */
i2c->CR1 |= I2C_CR1_PE;
}
int i2c_acquire(i2c_t dev)
{
assert(dev < I2C_NUMOF);
mutex_lock(&locks[dev]);
periph_clk_en(i2c_config[dev].bus, i2c_config[dev].rcc_mask);
return 0;
}
void i2c_release(i2c_t dev)
{
assert(dev < I2C_NUMOF);
periph_clk_dis(i2c_config[dev].bus, i2c_config[dev].rcc_mask);
mutex_unlock(&locks[dev]);
}
int i2c_write_regs(i2c_t dev, uint16_t addr, uint16_t reg,
const void *data, size_t len, uint8_t flags)
{
assert(dev < I2C_NUMOF);
if (flags & (I2C_NOSTOP | I2C_NOSTART)) {
return -EOPNOTSUPP;
}
I2C_TypeDef *i2c = i2c_config[dev].dev;
assert(i2c != NULL);
DEBUG("[i2c] write_regs: Starting\n");
/* As a higher level function we know the bus should be free */
if (i2c->ISR & I2C_ISR_BUSY) {
return -EAGAIN;
}
/* Handle endianness of register if 16 bit */
if (flags & I2C_REG16) {
reg = htons(reg); /* Make sure register is in big-endian on I2C bus */
}
/* First set ADDR and register with no stop */
/* No RELOAD should be set so repeated start is valid */
int ret = _write(i2c, addr, &reg, (flags & I2C_REG16) ? 2 : 1,
flags | I2C_NOSTOP, I2C_CR2_RELOAD);
if (ret < 0) {
return ret;
}
/* Then get the data from device */
return _write(i2c, addr, data, len, I2C_NOSTART, 0);
}
int i2c_read_bytes(i2c_t dev, uint16_t address, void *data,
size_t length, uint8_t flags)
{
assert(dev < I2C_NUMOF && length < MAX_BYTES_PER_FRAME);
I2C_TypeDef *i2c = i2c_config[dev].dev;
assert(i2c != NULL);
/* If reload was set, cannot send a repeated start */
if ((i2c->ISR & I2C_ISR_TCR) && !(flags & I2C_NOSTART)) {
return -EOPNOTSUPP;
}
DEBUG("[i2c] read_bytes: Starting\n");
/* RELOAD is needed because we don't know the full frame */
int ret = _start(i2c, (address << 1) | (length << I2C_CR2_NBYTES_Pos) |
I2C_CR2_RELOAD | I2C_FLAG_READ, flags);
if (ret < 0) {
return ret;
}
for (size_t i = 0; i < length; i++) {
/* wait for transfer to finish */
DEBUG("[i2c] read_bytes: Waiting for DR to be full\n");
ret = _wait_isr_set(i2c, I2C_ISR_RXNE, flags);
if (ret < 0) {
return ret;
}
/* read data from data register */
((uint8_t*)data)[i]= i2c->RXDR;
DEBUG("[i2c] read_bytes: DR full, read 0x%02X\n", ((uint8_t*)data)[i]);
}
if (flags & I2C_NOSTOP) {
/* With NOSTOP, the TCR indicates that the next command is ready */
/* TCR is needed because RELOAD is set preventing a NACK on last byte */
return _wait_isr_set(i2c, I2C_ISR_TCR, flags);
}
/* Wait until stop before other commands are sent */
ret = _wait_isr_set(i2c, I2C_ISR_STOPF, flags);
if (ret < 0) {
return ret;
}
return _wait_for_bus(i2c);
}
/**
* Cannot support continuous writes or frame splitting at this level. If an
* I2C_NOSTOP has been sent it must be followed by a repeated start or stop.
*/
int i2c_write_bytes(i2c_t dev, uint16_t address, const void *data,
size_t length, uint8_t flags)
{
assert(dev < I2C_NUMOF);
I2C_TypeDef *i2c = i2c_config[dev].dev;
DEBUG("[i2c] write_bytes: Starting\n");
return _write(i2c, address, data, length, flags, 0);
}
static int _write(I2C_TypeDef *i2c, uint16_t addr, const void *data,
size_t length, uint8_t flags, uint32_t cr2_flags)
{
assert(i2c != NULL && length < MAX_BYTES_PER_FRAME);
/* If reload was NOT set, must either stop or start */
if ((i2c->ISR & I2C_ISR_TC) && (flags & I2C_NOSTART)) {
return -EOPNOTSUPP;
}
int ret = _start(i2c, (addr << 1) | (length << I2C_CR2_NBYTES_Pos) |
cr2_flags, flags);
if (ret < 0) {
return ret;
}
for (size_t i = 0; i < length; i++) {
DEBUG("[i2c] write_bytes: Waiting for TX reg to be free\n");
ret = _wait_isr_set(i2c, I2C_ISR_TXIS, flags);
if (ret < 0) {
return ret;
}
DEBUG("[i2c] write_bytes: TX is free so send byte\n");
/* write data to data register */
i2c->TXDR = ((uint8_t*)data)[i];
}
if (flags & I2C_NOSTOP) {
if (cr2_flags & I2C_CR2_RELOAD) {
DEBUG("[i2c] write_bytes: Waiting for TCR\n");
/* With NOSTOP, the TCR indicates that the next command is ready */
/* TCR is needed because RELOAD allows loading more bytes */
return _wait_isr_set(i2c, I2C_ISR_TCR, flags);
}
else {
DEBUG("[i2c] write_bytes: Waiting for TC\n");
/* With NOSTOP, the TC indicates that the next command is ready */
/* TC is needed because no reload is set for repeated start */
return _wait_isr_set(i2c, I2C_ISR_TC, flags);
}
}
DEBUG("[i2c] write_bytes: Waiting for stop\n");
/* Wait until stop before other commands are sent */
ret = _wait_isr_set(i2c, I2C_ISR_STOPF, flags);
if (ret < 0) {
return ret;
}
return _wait_for_bus(i2c);
}
static int _start(I2C_TypeDef *i2c, uint32_t cr2, uint8_t flags)
{
assert(i2c != NULL);
assert((i2c->ISR & I2C_ISR_BUSY) || !(flags & I2C_NOSTART));
i2c->ICR |= CLEAR_FLAG;
if (flags & I2C_ADDR10) {
return -EOPNOTSUPP;
}
if (!(flags & I2C_NOSTART)) {
DEBUG("[i2c] start: Generate start condition\n");
/* Generate start condition */
cr2 |= I2C_CR2_START;
}
if (!(flags & I2C_NOSTOP)) {
cr2 |= I2C_CR2_AUTOEND;
cr2 &= ~(I2C_CR2_RELOAD);
}
DEBUG("[i2c] start: Setting CR2=0x%08x\n", (unsigned int)cr2);
i2c->CR2 = cr2;
if (!(flags & I2C_NOSTART)) {
uint16_t tick = TICK_TIMEOUT;
while ((i2c->CR2 & I2C_CR2_START) && tick--) {
if (!tick) {
/* Try to stop for state error recovery */
_stop(i2c);
return -ETIMEDOUT;
}
}
DEBUG("[i2c] start: Start condition and address generated\n");
/* Check if the device is there */
if ((i2c->ISR & I2C_ISR_NACKF)) {
i2c->ICR |= I2C_ICR_NACKCF;
_stop(i2c);
return -ENXIO;
}
}
return 0;
}
static int _stop(I2C_TypeDef *i2c)
{
/* Send stop condition */
DEBUG("[i2c] stop: Generate stop condition\n");
i2c->CR2 |= I2C_CR2_STOP;
/* Wait for the stop to complete */
uint16_t tick = TICK_TIMEOUT;
while ((i2c->CR2 & I2C_CR2_STOP) && tick--) {}
if (!tick) {
return -ETIMEDOUT;
}
DEBUG("[i2c] stop: Stop condition succeeded\n");
if (_wait_for_bus(i2c) < 0) {
return -ETIMEDOUT;
}
DEBUG("[i2c] stop: Bus is free\n");
return 0;
}
static int _wait_isr_set(I2C_TypeDef *i2c, uint32_t mask, uint8_t flags)
{
uint16_t tick = TICK_TIMEOUT;
while (tick--) {
uint32_t isr = i2c->ISR;
if (isr & I2C_ISR_NACKF) {
DEBUG("[i2c] wait_isr_set: NACK received\n");
/* Some devices have a valid data nack, if indicated don't stop */
if (!(flags & I2C_NOSTOP)) {
_stop(i2c);
}
i2c->ICR |= CLEAR_FLAG;
return -EIO;
}
if ((isr & I2C_ISR_ARLO) || (isr & I2C_ISR_BERR)) {
DEBUG("[i2c] wait_isr_set: Arbitration lost or bus error\n");
_stop(i2c);
i2c->ICR |= CLEAR_FLAG;
return -EAGAIN;
}
if (isr & mask) {
DEBUG("[i2c] wait_isr_set: ISR 0x%08x set\n", (unsigned int)mask);
return 0;
}
}
/*
* If timeout occurs this means a problem that must be handled on a higher
* level. A SWRST is recommended by the datasheet.
*/
return -ETIMEDOUT;
}
static inline int _wait_for_bus(I2C_TypeDef *i2c)
{
uint16_t tick = TICK_TIMEOUT;
while (tick-- && (i2c->ISR & I2C_ISR_BUSY)) {}
if (!tick) {
return -ETIMEDOUT;
}
return 0;
}
static inline void irq_handler(i2c_t dev)
{
assert(dev < I2C_NUMOF);
I2C_TypeDef *i2c = i2c_config[dev].dev;
unsigned state = i2c->ISR;
DEBUG("\n\n### I2C ERROR OCCURRED ###\n");
DEBUG("status: %08x\n", state);
if (state & I2C_ISR_OVR) {
DEBUG("OVR\n");
}
if (state & I2C_ISR_NACKF) {
DEBUG("AF\n");
}
if (state & I2C_ISR_ARLO) {
DEBUG("ARLO\n");
}
if (state & I2C_ISR_BERR) {
DEBUG("BERR\n");
}
if (state & I2C_ISR_PECERR) {
DEBUG("PECERR\n");
}
if (state & I2C_ISR_TIMEOUT) {
DEBUG("TIMEOUT\n");
}
if (state & I2C_ISR_ALERT) {
DEBUG("SMBALERT\n");
}
core_panic(PANIC_GENERAL_ERROR, "I2C FAULT");
}
#ifdef I2C_0_ISR
void I2C_0_ISR(void)
{
irq_handler(I2C_DEV(0));
}
#endif /* I2C_0_ISR */
#ifdef I2C_1_ISR
void I2C_1_ISR(void)
{
irq_handler(I2C_DEV(1));
}
#endif /* I2C_1_ISR */

View File

@ -1,478 +0,0 @@
/*
* Copyright (C) 2017 Kaspar Schleiser <kaspar@schleiser.de>
* 2014 FU Berlin
* 2018 Inria
* 2018 HAW Hamburg
*
* 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 cpu_stm32_common
* @ingroup drivers_periph_i2c
* @{
*
* @file
* @brief Low-level I2C driver implementation
*
* This driver supports the STM32 F1, F2, L1, and F4 families.
*
* @note This implementation only implements the 7-bit addressing polling mode.
*
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Toon Stegen <toon.stegen@altran.com>
* @author Vincent Dupont <vincent@otakeys.com>
* @author Víctor Ariño <victor.arino@triagnosys.com>
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
* @author Kevin Weiss <kevin.weiss@haw-hamburg.de>
*
* @}
*/
#include <assert.h>
#include <stdint.h>
#include <errno.h>
#include "cpu.h"
#include "irq.h"
#include "mutex.h"
#include "pm_layered.h"
#include "periph/i2c.h"
#include "periph/gpio.h"
#include "periph_conf.h"
/* Some DEBUG statements may cause delays that alter i2c functionality */
#define ENABLE_DEBUG (0)
#include "debug.h"
#define TICK_TIMEOUT (0xFFFF)
#define I2C_IRQ_PRIO (1)
#define I2C_FLAG_READ (I2C_READ)
#define I2C_FLAG_WRITE (0)
#define ERROR_FLAG (I2C_SR1_AF | I2C_SR1_ARLO | I2C_SR1_BERR)
/* static function definitions */
static void _init(i2c_t dev);
static void _i2c_init(I2C_TypeDef *i2c, uint32_t clk, uint32_t ccr);
static int _start(I2C_TypeDef *dev, uint8_t address_byte, uint8_t flags,
size_t length);
static int _stop(I2C_TypeDef *dev);
static int _is_sr1_mask_set(I2C_TypeDef *i2c, uint32_t mask, uint8_t flags);
static inline int _wait_for_bus(I2C_TypeDef *i2c);
static void _init_pins(i2c_t dev);
/**
* @brief Array holding one pre-initialized mutex for each I2C device
*/
static mutex_t locks[I2C_NUMOF];
void i2c_init(i2c_t dev)
{
assert(dev < I2C_NUMOF);
mutex_init(&locks[dev]);
assert(i2c_config[dev].dev != NULL);
periph_clk_en(i2c_config[dev].bus, i2c_config[dev].rcc_mask);
NVIC_SetPriority(i2c_config[dev].irqn, I2C_IRQ_PRIO);
NVIC_EnableIRQ(i2c_config[dev].irqn);
_init(dev);
#if defined(CPU_FAM_STM32F4)
/* make sure the analog filters don't hang -> see errata sheet 2.14.7 */
if (i2c_config[dev].dev->SR2 & I2C_SR2_BUSY) {
/* disable peripheral */
i2c_config[dev].dev->CR1 &= ~I2C_CR1_PE;
/* toggle both pins to reset analog filter */
gpio_init(i2c_config[dev].scl_pin, GPIO_OD);
gpio_init(i2c_config[dev].sda_pin, GPIO_OD);
gpio_set(i2c_config[dev].sda_pin);
gpio_set(i2c_config[dev].scl_pin);
gpio_clear(i2c_config[dev].sda_pin);
gpio_clear(i2c_config[dev].scl_pin);
gpio_set(i2c_config[dev].sda_pin);
gpio_set(i2c_config[dev].scl_pin);
_init(dev);
}
#endif
}
static void _init_pins(i2c_t dev)
{
/* configure pins */
gpio_init(i2c_config[dev].scl_pin, GPIO_OD_PU);
gpio_init(i2c_config[dev].sda_pin, GPIO_OD_PU);
#ifdef CPU_FAM_STM32F1
/* This is needed in case the remapped pins are used */
if (i2c_config[dev].scl_pin == GPIO_PIN(PORT_B, 8) ||
i2c_config[dev].sda_pin == GPIO_PIN(PORT_B, 9)) {
/* The remapping periph clock must first be enabled */
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
/* Then the remap can occur */
AFIO->MAPR |= AFIO_MAPR_I2C1_REMAP;
}
gpio_init_af(i2c_config[dev].scl_pin, GPIO_AF_OUT_OD);
gpio_init_af(i2c_config[dev].sda_pin, GPIO_AF_OUT_OD);
#else
gpio_init_af(i2c_config[dev].scl_pin, i2c_config[dev].scl_af);
gpio_init_af(i2c_config[dev].sda_pin, i2c_config[dev].sda_af);
#endif
}
static void _i2c_init(I2C_TypeDef *i2c, uint32_t clk, uint32_t ccr)
{
/* disable device and set ACK bit */
i2c->CR1 = I2C_CR1_ACK;
/* configure I2C clock */
i2c->CR2 = (clk / 1000000) | I2C_CR2_ITERREN;
i2c->CCR = ccr;
i2c->TRISE = (clk / 1000000) + 1;
/* configure device */
/* configure device */
i2c->OAR1 |= (1 << 14); /* datasheet: bit 14 should be kept 1 */
i2c->OAR1 &= ~I2C_OAR1_ADDMODE; /* make sure we are in 7-bit address mode */
/* Clear flags */
i2c->SR1 &= ~ERROR_FLAG;
/* enable device */
i2c->CR1 |= I2C_CR1_PE;
}
static void _init(i2c_t dev)
{
I2C_TypeDef *i2c = i2c_config[dev].dev;
uint32_t ccr = 0;
/* read speed configuration */
switch (i2c_config[dev].speed) {
case I2C_SPEED_LOW:
/* 10Kbit/s */
ccr = i2c_config[dev].clk / 20000;
break;
case I2C_SPEED_NORMAL:
/* 100Kbit/s */
ccr = i2c_config[dev].clk / 200000;
break;
case I2C_SPEED_FAST:
ccr = i2c_config[dev].clk / 800000;
break;
}
/* make peripheral soft reset */
i2c->CR1 |= I2C_CR1_SWRST;
_init_pins(dev);
i2c->CR1 &= ~I2C_CR1_SWRST;
/* configure device */
_i2c_init(i2c, i2c_config[dev].clk, ccr);
}
int i2c_acquire(i2c_t dev)
{
assert(dev < I2C_NUMOF);
mutex_lock(&locks[dev]);
#ifdef STM32_PM_STOP
/* block STOP mode */
pm_block(STM32_PM_STOP);
#endif
periph_clk_en(i2c_config[dev].bus, i2c_config[dev].rcc_mask);
return 0;
}
void i2c_release(i2c_t dev)
{
assert(dev < I2C_NUMOF);
periph_clk_dis(i2c_config[dev].bus, i2c_config[dev].rcc_mask);
#ifdef STM32_PM_STOP
/* unblock STOP mode */
pm_unblock(STM32_PM_STOP);
#endif
mutex_unlock(&locks[dev]);
}
int i2c_read_bytes(i2c_t dev, uint16_t address, void *data, size_t length,
uint8_t flags)
{
assert(dev < I2C_NUMOF);
I2C_TypeDef *i2c = i2c_config[dev].dev;
DEBUG("[i2c] read_bytes: Starting\n");
/* Do not support repeated start reading
* The repeated start read requires the bus to be busy (I2C_SR2_BUSY == 1)
* the previous R/W state to be a read (I2C_SR2_TRA == 0)
* and for the command not to be split frame (I2C_NOSTART == 0)
*/
if (((i2c->SR2 & (I2C_SR2_BUSY | I2C_SR2_TRA)) == I2C_SR2_BUSY) &&
!(flags & I2C_NOSTART)) {
return -EOPNOTSUPP;
}
int ret = _start(i2c, (address << 1) | I2C_FLAG_READ, flags, length);
if (ret < 0) {
if (ret == -ETIMEDOUT) {
_init(dev);
}
return ret;
}
for (size_t i = 0; i < length; i++) {
if (i + 1 == length && !(flags & I2C_NOSTOP)) {
/* If data is already in the buffer we must clear before sending
a stop. If I2C_NOSTOP was called up to two extra bytes may be
clocked out on the line however they get ignored in the firmware.*/
if ((i2c->SR1 & I2C_SR1_RXNE) && (length == 1)) {
((uint8_t*)data)[i] = i2c->DR;
return _stop(i2c);
}
/* Stop must also be sent before final read */
ret = _stop(i2c);
if (ret < 0) {
return ret;
}
}
/* Wait for reception to complete */
ret = _is_sr1_mask_set(i2c, I2C_SR1_RXNE, flags);
if (ret < 0) {
return ret;
}
((uint8_t*)data)[i] = i2c->DR;
}
DEBUG("[i2c] read_bytes: Finished reading bytes\n");
if (flags & I2C_NOSTOP) {
return 0;
}
return _wait_for_bus(i2c);
}
int i2c_write_bytes(i2c_t dev, uint16_t address, const void *data,
size_t length, uint8_t flags)
{
assert(dev < I2C_NUMOF);
int ret;
I2C_TypeDef *i2c = i2c_config[dev].dev;
assert(i2c != NULL);
DEBUG("[i2c] write_bytes: Starting\n");
/* Length is 0 in start since we don't need to preset the stop bit */
ret = _start(i2c, (address << 1) | I2C_FLAG_WRITE, flags, 0);
if (ret < 0) {
if (ret == -ETIMEDOUT) {
_init(dev);
}
return ret;
}
/* Send out data bytes */
for (size_t i = 0; i < length; i++) {
DEBUG("[i2c] write_bytes: Waiting for TX reg to be free\n");
ret = _is_sr1_mask_set(i2c, I2C_SR1_TXE, flags);
if (ret < 0) {
return ret;
}
DEBUG("[i2c] write_bytes: TX is free so send byte\n");
i2c->DR = ((uint8_t*)data)[i];
}
/* Wait for tx reg to be empty so other calls will no interfere */
ret = _is_sr1_mask_set(i2c, I2C_SR1_TXE, flags);
if (ret < 0) {
return ret;
}
if (flags & I2C_NOSTOP) {
return 0;
}
else {
/* End transmission */
DEBUG("[i2c] write_bytes: Ending transmission\n");
ret = _stop(i2c);
if (ret < 0) {
return ret;
}
DEBUG("[i2c] write_bytes: STOP condition was send out\n");
}
return _wait_for_bus(i2c);
}
static int _start(I2C_TypeDef *i2c, uint8_t address_byte, uint8_t flags,
size_t length)
{
assert(i2c != NULL);
if ((flags & I2C_ADDR10) ||
(!(i2c->SR2 & I2C_SR2_BUSY) && (flags & I2C_NOSTART))) {
return -EOPNOTSUPP;
}
/* Clear flags */
i2c->SR1 &= ~ERROR_FLAG;
if (!(flags & I2C_NOSTART)) {
DEBUG("[i2c] start: Generate start condition\n");
/* Generate start condition */
i2c->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
/* Wait for SB flag to be set */
int ret = _is_sr1_mask_set(i2c, I2C_SR1_SB, flags & ~I2C_NOSTOP);
if (ret < 0) {
return ret;
}
DEBUG("[i2c] start: Start condition generated\n");
DEBUG("[i2c] start: Generating address\n");
/* Send address and read/write flag */
i2c->DR = (address_byte);
if (!(flags & I2C_NOSTOP) && length == 1) {
i2c->CR1 &= ~(I2C_CR1_ACK);
}
/* Wait for ADDR flag to be set */
ret = _is_sr1_mask_set(i2c, I2C_SR1_ADDR, flags & ~I2C_NOSTOP);
if (ret == -EIO){
/* Since NACK happened during start it means no device connected */
return -ENXIO;
}
/* Needed to clear address bit */
i2c->SR2;
if (!(flags & I2C_NOSTOP) && length == 1) {
/* Stop must also be sent before final read */
i2c->CR1 |= (I2C_CR1_STOP);
}
DEBUG("[i2c] start: Address generated\n");
return ret;
}
return 0;
}
static int _is_sr1_mask_set(I2C_TypeDef *i2c, uint32_t mask, uint8_t flags)
{
DEBUG("[i2c] _is_sr1_mask_set: waiting to set %04X\n", (uint16_t)mask);
uint16_t tick = TICK_TIMEOUT;
while (tick--) {
uint32_t sr1 = i2c->SR1;
if (sr1 & I2C_SR1_AF) {
DEBUG("[i2c] is_sr1_mask_set: NACK received\n");
i2c->SR1 &= ~ERROR_FLAG;
if (!(flags & I2C_NOSTOP)) {
_stop(i2c);
}
return -EIO;
}
if ((sr1 & I2C_SR1_ARLO) || (sr1 & I2C_SR1_BERR)) {
DEBUG("[i2c] is_sr1_mask_set: arb lost or bus ERROR_FLAG\n");
i2c->SR1 &= ~ERROR_FLAG;
_stop(i2c);
return -EAGAIN;
}
if (sr1 & mask) {
i2c->SR1 &= ~ERROR_FLAG;
return 0;
}
}
/*
* If timeout occurs this means a problem that must be handled on a higher
* level. A SWRST is recommended by the datasheet.
*/
i2c->SR1 &= ~ERROR_FLAG;
_stop(i2c);
return -ETIMEDOUT;
}
static int _stop(I2C_TypeDef *i2c)
{
/* send STOP condition */
DEBUG("[i2c] stop: Generate stop condition\n");
i2c->CR1 &= ~(I2C_CR1_ACK);
i2c->CR1 |= I2C_CR1_STOP;
uint16_t tick = TICK_TIMEOUT;
while ((i2c->CR1 & I2C_CR1_STOP) && tick--) {}
if (!tick) {
return -ETIMEDOUT;
}
DEBUG("[i2c] stop: Stop condition succeeded\n");
if (_wait_for_bus(i2c) < 0) {
return -ETIMEDOUT;
}
DEBUG("[i2c] stop: Bus is free\n");
return 0;
}
static inline int _wait_for_bus(I2C_TypeDef *i2c)
{
uint16_t tick = TICK_TIMEOUT;
while ((i2c->SR2 & I2C_SR2_BUSY) && tick--) {}
if (!tick) {
return -ETIMEDOUT;
}
return 0;
}
#if I2C_0_ISR || I2C_1_ISR
static inline void irq_handler(i2c_t dev)
{
assert(dev < I2C_NUMOF);
I2C_TypeDef *i2c = i2c_config[dev].dev;
assert(i2c != NULL);
unsigned state = i2c->SR1;
DEBUG("\n\n### I2C ERROR OCCURRED ###\n");
DEBUG("status: %08x\n", state);
if (state & I2C_SR1_OVR) {
DEBUG("OVR\n");
}
if (state & I2C_SR1_AF) {
DEBUG("AF\n");
}
if (state & I2C_SR1_ARLO) {
DEBUG("ARLO\n");
}
if (state & I2C_SR1_BERR) {
DEBUG("BERR\n");
}
if (state & I2C_SR1_PECERR) {
DEBUG("PECERR\n");
}
if (state & I2C_SR1_TIMEOUT) {
DEBUG("TIMEOUT\n");
}
if (state & I2C_SR1_SMBALERT) {
DEBUG("SMBALERT\n");
}
core_panic(PANIC_GENERAL_ERROR, "I2C FAULT");
}
#endif
#if I2C_0_ISR
void I2C_0_ISR(void)
{
irq_handler(I2C_DEV(0));
}
#endif /* I2C_0_ISR */
#if I2C_1_ISR
void I2C_1_ISR(void)
{
irq_handler(I2C_DEV(1));
}
#endif /* I2C_1_ISR */

View File

@ -1,146 +0,0 @@
/*
* Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
* 2015 Freie Universität Berlin
* 2015 Engineering-Spirit
* 2017-2019 OTA keys S.A.
* 2019 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 cpu_stm32_common
* @ingroup drivers_periph_pm
* @{
*
* @file
* @brief Implementation of the kernels power management interface
*
* @author Nick v. IJzendoorn <nijzndoorn@engineering-spirit.nl>
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Fabian Nack <nack@inf.fu-berlin.de>
* @author Vincent Dupont <vincent@otakeys.com>
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
*
* @}
*/
#include "irq.h"
#include "periph/pm.h"
#include "stmclk.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#ifndef PM_STOP_CONFIG
/**
* @brief Define config flags for stop mode
*
* Available values can be found in reference manual, PWR section, register CR.
*/
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3)
#define PM_STOP_CONFIG (PWR_CR_LPDS)
#elif defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
/* Enable ultra low-power and clear wakeup flags */
#define PM_STOP_CONFIG (PWR_CR_LPSDSR | PWR_CR_ULP | PWR_CR_CWUF)
#elif defined(CPU_FAM_STM32L4)
#define PM_STOP_CONFIG (PWR_CR1_LPMS_STOP1)
#elif defined(CPU_FAM_STM32WB)
#define PM_STOP_CONFIG (PWR_CR1_LPMS_0)
#elif defined(CPU_FAM_STM32F7)
#define PM_STOP_CONFIG (PWR_CR1_LPDS | PWR_CR1_FPDS | PWR_CR1_LPUDS)
#elif defined(CPU_FAM_STM32WB)
#else
#define PM_STOP_CONFIG (PWR_CR_LPDS | PWR_CR_FPDS)
#endif
#endif
#ifndef PM_STANDBY_CONFIG
/**
* @brief Define config flags for standby mode
*
* Available values can be found in reference manual, PWR section, register CR.
*/
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
#define PM_STANDBY_CONFIG (PWR_CR_PDDS | PWR_CR_CWUF | PWR_CR_CSBF | PWR_CR_ULP)
#elif defined(CPU_FAM_STM32L4)
#define PM_STANDBY_CONFIG (PWR_CR1_LPMS_STANDBY)
#elif defined(CPU_FAM_STM32WB)
#define PM_STANDBY_CONFIG (PWR_CR1_LPMS_0 | PWR_CR1_LPMS_1)
#elif defined(CPU_FAM_STM32F7)
#define PM_STANDBY_CONFIG (PWR_CR1_PDDS | PWR_CR1_CSBF)
#else
#define PM_STANDBY_CONFIG (PWR_CR_PDDS | PWR_CR_CWUF | PWR_CR_CSBF)
#endif
#endif
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
#define PWR_CR_REG PWR->CR1
#define PWR_WUP_REG PWR->CR3
/* Allow overridable SRAM2 retention mode using CFLAGS */
#ifndef STM32L4_SRAM2_RETENTION
/* Disable SRAM2 retention by default for maximum power saving */
#define STM32L4_SRAM2_RETENTION (0)
#endif
#elif defined(CPU_FAM_STM32F7)
#define PWR_CR_REG PWR->CR1
#define PWR_WUP_REG PWR->CSR2
#else
#define PWR_CR_REG PWR->CR
#define PWR_WUP_REG PWR->CSR
#endif
void pm_set(unsigned mode)
{
int deep;
switch (mode) {
#ifdef STM32_PM_STANDBY
case STM32_PM_STANDBY:
PWR_CR_REG &= ~(PM_STOP_CONFIG | PM_STANDBY_CONFIG);
PWR_CR_REG |= PM_STANDBY_CONFIG;
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
#if STM32L4_SRAM2_RETENTION
PWR->CR3 |= PWR_CR3_RRS;
#else
PWR->CR3 &= ~PWR_CR3_RRS;
#endif
#endif
#if defined(CPU_FAM_STM32L4)
/* Clear flags */
PWR->SCR |= PWR_SCR_CSBF;
#endif
/* Enable WKUP pin to use for wakeup from standby mode */
PWR_WUP_REG |= PM_EWUP_CONFIG;
/* Set SLEEPDEEP bit of system control block */
deep = 1;
break;
#endif
#ifdef STM32_PM_STOP
case STM32_PM_STOP:
PWR_CR_REG &= ~(PM_STOP_CONFIG | PM_STANDBY_CONFIG);
PWR_CR_REG |= PM_STOP_CONFIG;
/* Set SLEEPDEEP bit of system control block */
deep = 1;
break;
#endif
default:
deep = 0;
break;
}
cortexm_sleep(deep);
if (deep) {
/* Re-init clock after STOP */
stmclk_init_sysclk();
}
}
void pm_off(void)
{
irq_disable();
pm_set(0);
}

View File

@ -1,138 +0,0 @@
/*
* Copyright (C) 2014-2016 Freie Universität Berlin
* 2015 Engineering-Spirit
* 2016 OTA keys S.A.
*
* 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 cpu_stm32_common
* @ingroup drivers_periph_pwm
* @{
*
* @file
* @brief Low-level PWM driver implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Fabian Nack <nack@inf.fu-berlin.de>
* @author Nick v. IJzendoorn <nijzendoorn@engineering-spirit.nl>
* @author Aurelien Gonce <aurelien.gonce@altran.fr>
*
* @}
*/
#include "cpu.h"
#include "assert.h"
#include "periph/pwm.h"
#include "periph/gpio.h"
#define CCMR_LEFT (TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 | \
TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2)
#define CCMR_RIGHT (TIM_CCMR1_OC1M_0 | TIM_CCMR1_OC1M_1 | \
TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC2M_0 | \
TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2);
static inline TIM_TypeDef *dev(pwm_t pwm)
{
return pwm_config[pwm].dev;
}
uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res)
{
uint32_t timer_clk = periph_timer_clk(pwm_config[pwm].bus);
/* verify parameters */
assert((pwm < PWM_NUMOF) && ((freq * res) < timer_clk));
/* power on the used timer */
periph_clk_en(pwm_config[pwm].bus, pwm_config[pwm].rcc_mask);
/* reset configuration and CC channels */
dev(pwm)->CR1 = 0;
dev(pwm)->CR2 = 0;
for (unsigned i = 0; i < TIMER_CHAN; ++i) {
dev(pwm)->CCR[i] = 0;
}
/* configure the used pins */
unsigned i = 0;
while ((i < TIMER_CHAN) && (pwm_config[pwm].chan[i].pin != GPIO_UNDEF)) {
gpio_init(pwm_config[pwm].chan[i].pin, GPIO_OUT);
gpio_init_af(pwm_config[pwm].chan[i].pin, pwm_config[pwm].af);
i++;
}
/* configure the PWM frequency and resolution by setting the auto-reload
* and prescaler registers */
dev(pwm)->PSC = (timer_clk / (res * freq)) - 1;
dev(pwm)->ARR = res - 1;
/* set PWM mode */
switch (mode) {
case PWM_LEFT:
dev(pwm)->CCMR1 = CCMR_LEFT;
dev(pwm)->CCMR2 = CCMR_LEFT;
break;
case PWM_RIGHT:
dev(pwm)->CCMR1 = CCMR_RIGHT;
dev(pwm)->CCMR2 = CCMR_RIGHT;
break;
case PWM_CENTER:
dev(pwm)->CCMR1 = 0;
dev(pwm)->CCMR2 = 0;
dev(pwm)->CR1 |= (TIM_CR1_CMS_0 | TIM_CR1_CMS_1);
break;
}
/* enable PWM outputs and start PWM generation */
#ifdef TIM_BDTR_MOE
dev(pwm)->BDTR = TIM_BDTR_MOE;
#endif
dev(pwm)->CCER = (TIM_CCER_CC1E | TIM_CCER_CC2E |
TIM_CCER_CC3E | TIM_CCER_CC4E);
dev(pwm)->CR1 |= TIM_CR1_CEN;
/* return the actual used PWM frequency */
return (timer_clk / (res * (dev(pwm)->PSC + 1)));
}
uint8_t pwm_channels(pwm_t pwm)
{
assert(pwm < PWM_NUMOF);
unsigned i = 0;
while ((i < TIMER_CHAN) && (pwm_config[pwm].chan[i].pin != GPIO_UNDEF)) {
i++;
}
return (uint8_t)i;
}
void pwm_set(pwm_t pwm, uint8_t channel, uint16_t value)
{
assert((pwm < PWM_NUMOF) &&
(channel < TIMER_CHAN) &&
(pwm_config[pwm].chan[channel].pin != GPIO_UNDEF));
/* norm value to maximum possible value */
if (value > dev(pwm)->ARR) {
value = (uint16_t)dev(pwm)->ARR;
}
/* set new value */
dev(pwm)->CCR[pwm_config[pwm].chan[channel].cc_chan] = value;
}
void pwm_poweron(pwm_t pwm)
{
assert(pwm < PWM_NUMOF);
periph_clk_en(pwm_config[pwm].bus, pwm_config[pwm].rcc_mask);
dev(pwm)->CR1 |= TIM_CR1_CEN;
}
void pwm_poweroff(pwm_t pwm)
{
assert(pwm < PWM_NUMOF);
dev(pwm)->CR1 &= ~TIM_CR1_CEN;
periph_clk_dis(pwm_config[pwm].bus, pwm_config[pwm].rcc_mask);
}

View File

@ -1,223 +0,0 @@
/*
* Copyright (C) 2017 Gilles DOFFE <gdoffe@gmail.com>
*
* 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 cpu_cortexm_common
* @ingroup drivers_periph_qdec
* @{
*
* @file
* @brief Low-level QDEC driver implementation
*
* @author Gilles DOFFE <gilles.doffe@gmail.com>
*
* @}
*/
#include <errno.h>
#include "cpu.h"
#include "assert.h"
#include "periph/qdec.h"
#include "periph/gpio.h"
#ifdef QDEC_NUMOF
/**
* @brief Interrupt context for each configured qdec
*/
static qdec_isr_ctx_t isr_ctx[QDEC_NUMOF];
/**
* @brief Read the current value of the given qdec device. Internal use.
*
* @param[in] dev the qdec to read the current value from
* @param[in] dev perform a reset of qdec counter if not 0
*
* @return the qdecs current value
*/
static int32_t _qdec_read(qdec_t qdec, uint8_t reset);
static inline TIM_TypeDef *dev(qdec_t qdec)
{
return qdec_config[qdec].dev;
}
int32_t qdec_init(qdec_t qdec, qdec_mode_t mode, qdec_cb_t cb, void *arg)
{
/* Control variables */
uint8_t i = 0;
/* Verify parameters */
assert((qdec < QDEC_NUMOF));
/* Power on the used timer */
periph_clk_en(qdec_config[qdec].bus, qdec_config[qdec].rcc_mask);
/* Reset configuration and CC channels */
dev(qdec)->CR1 = 0;
dev(qdec)->CR2 = 0;
dev(qdec)->SMCR = 0;
dev(qdec)->CCER = 0;
for (i = 0; i < QDEC_CHAN; i++) {
dev(qdec)->CCR[i] = 0;
}
/* Count on A (TI1) signal edges, B (TI2) signal edges or both,
* default to EINVAL (Invalid argument).
*/
switch (mode) {
/* X2 mode */
case QDEC_X2:
dev(qdec)->SMCR |= (0x02 << TIM_SMCR_SMS_Pos);
break;
/* X4 mode */
case QDEC_X4:
dev(qdec)->SMCR |= (0x03 << TIM_SMCR_SMS_Pos);
break;
/* X1 mode does not exist on STM32 as STM32 always counts
* on both rising and falling edges from encoder
*/
case QDEC_X1:
default:
errno = EINVAL;
goto err_invalid_mode;
}
/* Reset configuration and CC channels */
for (i = 0; i < QDEC_CHAN; i++) {
dev(qdec)->CCR[i] = 0;
}
/* Configure the used pins */
i = 0;
while ((i < QDEC_CHAN) && (qdec_config[qdec].chan[i].pin != GPIO_UNDEF)) {
gpio_init(qdec_config[qdec].chan[i].pin, GPIO_IN);
gpio_init_af(qdec_config[qdec].chan[i].pin, qdec_config[qdec].af);
i++;
}
/* Set counting max value */
dev(qdec)->ARR = qdec_config[qdec].max;
/* Set TIMx_CNT value to half of of TIMx_ARR to permit countdown */
dev(qdec)->CNT = dev(qdec)->ARR / 2;
/* Remember the interrupt context */
isr_ctx[qdec].cb = cb;
isr_ctx[qdec].arg = arg;
/* Enable the qdec's interrupt */
NVIC_EnableIRQ(qdec_config[qdec].irqn);
dev(qdec)->DIER |= TIM_DIER_UIE;
/* Reset counter and start qdec */
qdec_start(qdec);
return 0;
/* Error management */
err_invalid_mode:
return errno;
}
inline int32_t qdec_read(qdec_t qdec)
{
return _qdec_read(qdec, false);
}
inline int32_t qdec_read_and_reset(qdec_t qdec)
{
return _qdec_read(qdec, true);
}
static int32_t _qdec_read(qdec_t qdec, uint8_t reset)
{
int32_t count = 0;
uint32_t irq_save = 0;
/* Protect critical section */
irq_save = irq_disable();
/* Get counter value */
count = dev(qdec)->CNT;
/* Reset counter if asked */
if (reset)
{
dev(qdec)->CNT = dev(qdec)->ARR / 2;
}
/* Restore IRQ */
irq_restore(irq_save);
/* Subtract offset before return */
count -= dev(qdec)->ARR / 2;
/* Return count minus offset */
return count;
}
void qdec_start(qdec_t qdec)
{
dev(qdec)->CR1 |= TIM_CR1_CEN;
}
void qdec_stop(qdec_t qdec)
{
dev(qdec)->CR1 &= ~TIM_CR1_CEN;
}
static inline void irq_handler(qdec_t qdec)
{
uint32_t status = (dev(qdec)->SR & dev(qdec)->DIER);
if (status & (TIM_SR_UIF)) {
dev(qdec)->SR &= ~(TIM_SR_UIF);
isr_ctx[qdec].cb(isr_ctx[qdec].arg);
}
cortexm_isr_end();
}
#ifdef QDEC_0_ISR
void QDEC_0_ISR(void)
{
irq_handler(0);
}
#endif
#ifdef QDEC_1_ISR
void QDEC_1_ISR(void)
{
irq_handler(1);
}
#endif
#ifdef QDEC_2_ISR
void QDEC_2_ISR(void)
{
irq_handler(2);
}
#endif
#ifdef QDEC_3_ISR
void QDEC_3_ISR(void)
{
irq_handler(3);
}
#endif
#ifdef QDEC_4_ISR
void QDEC_4_ISR(void)
{
irq_handler(4);
}
#endif
#endif /* QDEC_NUMOF */

View File

@ -1,358 +0,0 @@
/*
* Copyright (C) 2015 Lari Lehtomäki
* 2016 Laksh Bhatia
* 2016-2017 OTA keys S.A.
* 2017 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.
*/
/**
* @ingroup cpu_stm32_common
* @{
* @file
* @brief Low-level RTC driver implementation
*
* @author Lari Lehtomäki <lari@lehtomaki.fi>
* @author Laksh Bhatia <bhatialaksh3@gmail.com>
* @author Vincent Dupont <vincent@otakeys.com>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @}
*/
#include <time.h>
#include "cpu.h"
#include "stmclk.h"
#include "periph/rtc.h"
/* this implementation does not work for the stm32f1 */
#if !defined(CPU_FAM_STM32F1)
/* map some CPU specific register names */
#if defined (CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
#define EN_REG (RCC->CSR)
#define EN_BIT (RCC_CSR_RTCEN)
#define CLKSEL_MASK (RCC_CSR_RTCSEL)
#define CLKSEL_LSE (RCC_CSR_RTCSEL_LSE)
#define CLKSEL_LSI (RCC_CSR_RTCSEL_LSI)
#else
#define EN_REG (RCC->BDCR)
#define EN_BIT (RCC_BDCR_RTCEN)
#define CLKSEL_MASK (RCC_BDCR_RTCSEL_0 | RCC_BDCR_RTCSEL_1)
#define CLKSEL_LSE (RCC_BDCR_RTCSEL_0)
#define CLKSEL_LSI (RCC_BDCR_RTCSEL_1)
#endif
/* interrupt line name mapping */
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0)
#define IRQN (RTC_IRQn)
#define ISR_NAME isr_rtc
#else
#define IRQN (RTC_Alarm_IRQn)
#define ISR_NAME isr_rtc_alarm
#endif
/* EXTI bitfield mapping */
#if defined(CPU_FAM_STM32L4)
#define EXTI_IMR_BIT (EXTI_IMR1_IM18)
#define EXTI_FTSR_BIT (EXTI_FTSR1_FT18)
#define EXTI_RTSR_BIT (EXTI_RTSR1_RT18)
#define EXTI_PR_BIT (EXTI_PR1_PIF18)
#elif defined(CPU_FAM_STM32WB)
#define EXTI_IMR_BIT (EXTI_IMR1_IM17)
#define EXTI_FTSR_BIT (EXTI_FTSR1_FT17)
#define EXTI_RTSR_BIT (EXTI_RTSR1_RT17)
#define EXTI_PR_BIT (EXTI_PR1_PIF17)
#else
#if defined(CPU_FAM_STM32L0)
#define EXTI_IMR_BIT (EXTI_IMR_IM17)
#else
#define EXTI_IMR_BIT (EXTI_IMR_MR17)
#endif
#define EXTI_FTSR_BIT (EXTI_FTSR_TR17)
#define EXTI_RTSR_BIT (EXTI_RTSR_TR17)
#define EXTI_PR_BIT (EXTI_PR_PR17)
#endif
/* write protection values */
#define WPK1 (0xCA)
#define WPK2 (0x53)
/* define TR, DR, and ALRMAR position and masks */
#define TR_H_MASK (RTC_TR_HU | RTC_TR_HT)
#define TR_M_MASK (RTC_TR_MNU | RTC_TR_MNT)
#define TR_S_MASK (RTC_TR_SU | RTC_TR_ST)
#define DR_Y_MASK (RTC_DR_YU | RTC_DR_YT)
#define DR_M_MASK (RTC_DR_MU | RTC_DR_MT)
#define DR_D_MASK (RTC_DR_DU | RTC_DR_DT)
#define ALRM_D_MASK (RTC_ALRMAR_DU | RTC_ALRMAR_DT)
#define ALRM_H_MASK (RTC_ALRMAR_HU | RTC_ALRMAR_HT)
#define ALRM_M_MASK (RTC_ALRMAR_MNU | RTC_ALRMAR_MNT)
#define ALRM_S_MASK (RTC_ALRMAR_SU | RTC_ALRMAR_ST)
#ifndef RTC_DR_YU_Pos
#define RTC_DR_YU_Pos (16U)
#endif
#ifndef RTC_DR_MU_Pos
#define RTC_DR_MU_Pos (8U)
#endif
#ifndef RTC_DR_DU_Pos
#define RTC_DR_DU_Pos (0U)
#endif
#ifndef RTC_TR_HU_Pos
#define RTC_TR_HU_Pos (16U)
#endif
#ifndef RTC_TR_MNU_Pos
#define RTC_TR_MNU_Pos (8U)
#endif
#ifndef RTC_TR_SU_Pos
#define RTC_TR_SU_Pos (0U)
#endif
#ifndef RTC_ALRMAR_DU_Pos
#define RTC_ALRMAR_DU_Pos (24U)
#endif
#ifndef RTC_ALRMAR_HU_Pos
#define RTC_ALRMAR_HU_Pos (16U)
#endif
#ifndef RTC_ALRMAR_MNU_Pos
#define RTC_ALRMAR_MNU_Pos (8U)
#endif
#ifndef RTC_ALRMAR_SU_Pos
#define RTC_ALRMAR_SU_Pos (0U)
#endif
/* figure out sync and async prescaler */
#if CLOCK_LSE
#define PRE_SYNC (255)
#define PRE_ASYNC (127)
#elif (CLOCK_LSI == 40000)
#define PRE_SYNC (319)
#define PRE_ASYNC (124)
#elif (CLOCK_LSI == 37000)
#define PRE_SYNC (295)
#define PRE_ASYNC (124)
#elif (CLOCK_LSI == 32000)
#define PRE_SYNC (249)
#define PRE_ASYNC (127)
#else
#error "rtc: unable to determine RTC SYNC and ASYNC prescalers from LSI value"
#endif
/* struct tm counts years since 1900 but RTC has only two-digit year hence the
* offset of 100 years. */
#define YEAR_OFFSET (100)
/* Use a magic number to determine the initial RTC source. This will be used
to know if a reset of the RTC is required at initialization. */
#if CLOCK_LSE
#define MAGIC_CLCK_NUMBER (0x1970)
#else
#define MAGIC_CLCK_NUMBER (0x1971)
#endif
static struct {
rtc_alarm_cb_t cb; /**< callback called from RTC interrupt */
void *arg; /**< argument passed to the callback */
} isr_ctx;
static uint32_t val2bcd(int val, int shift, uint32_t mask)
{
uint32_t bcdhigh = 0;
while (val >= 10) {
bcdhigh++;
val -= 10;
}
return ((((bcdhigh << 4) | val) << shift) & mask);
}
static int bcd2val(uint32_t val, int shift, uint32_t mask)
{
int tmp = (int)((val & mask) >> shift);
return (((tmp >> 4) * 10) + (tmp & 0x0f));
}
static inline void rtc_unlock(void)
{
/* enable backup clock domain */
stmclk_dbp_unlock();
/* unlock RTC */
RTC->WPR = WPK1;
RTC->WPR = WPK2;
/* enter RTC init mode */
RTC->ISR |= RTC_ISR_INIT;
while (!(RTC->ISR & RTC_ISR_INITF)) {}
}
static inline void rtc_lock(void)
{
/* exit RTC init mode */
RTC->ISR &= ~RTC_ISR_INIT;
while (RTC->ISR & RTC_ISR_INITF) {}
/* lock RTC device */
RTC->WPR = 0xff;
/* disable backup clock domain */
stmclk_dbp_lock();
}
void rtc_init(void)
{
stmclk_dbp_unlock();
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
/* Compare the stored magic number with the current one. If it's different
it means the clock source has changed and thus a RTC reset is
required. */
if (RTC->BKP0R != MAGIC_CLCK_NUMBER) {
RCC->CSR |= RCC_CSR_RTCRST;
RCC->CSR &= ~RCC_CSR_RTCRST;
RTC->BKP0R = MAGIC_CLCK_NUMBER; /* Store the new magic number */
}
#endif
stmclk_dbp_lock();
/* enable low frequency clock */
stmclk_enable_lfclk();
/* select input clock and enable the RTC */
stmclk_dbp_unlock();
EN_REG &= ~(CLKSEL_MASK);
#if CLOCK_LSE
EN_REG |= (CLKSEL_LSE | EN_BIT);
#else
EN_REG |= (CLKSEL_LSI | EN_BIT);
#endif
rtc_unlock();
/* reset configuration */
RTC->CR = 0;
RTC->ISR = RTC_ISR_INIT;
/* configure prescaler (RTC PRER) */
RTC->PRER = (PRE_SYNC | (PRE_ASYNC << 16));
rtc_lock();
/* configure the EXTI channel, as RTC interrupts are routed through it.
* Needs to be configured to trigger on rising edges. */
EXTI->FTSR &= ~(EXTI_FTSR_BIT);
EXTI->RTSR |= EXTI_RTSR_BIT;
EXTI->IMR |= EXTI_IMR_BIT;
EXTI->PR = EXTI_PR_BIT;
/* enable global RTC interrupt */
NVIC_EnableIRQ(IRQN);
}
int rtc_set_time(struct tm *time)
{
/* normalize input */
rtc_tm_normalize(time);
rtc_unlock();
RTC->DR = (val2bcd((time->tm_year % 100), RTC_DR_YU_Pos, DR_Y_MASK) |
val2bcd(time->tm_mon + 1, RTC_DR_MU_Pos, DR_M_MASK) |
val2bcd(time->tm_mday, RTC_DR_DU_Pos, DR_D_MASK));
RTC->TR = (val2bcd(time->tm_hour, RTC_TR_HU_Pos, TR_H_MASK) |
val2bcd(time->tm_min, RTC_TR_MNU_Pos, TR_M_MASK) |
val2bcd(time->tm_sec, RTC_TR_SU_Pos, TR_S_MASK));
rtc_lock();
while (!(RTC->ISR & RTC_ISR_RSF)) {}
return 0;
}
int rtc_get_time(struct tm *time)
{
/* save current time */
uint32_t tr = RTC->TR;
uint32_t dr = RTC->DR;
time->tm_year = bcd2val(dr, RTC_DR_YU_Pos, DR_Y_MASK) + YEAR_OFFSET;
time->tm_mon = bcd2val(dr, RTC_DR_MU_Pos, DR_M_MASK) - 1;
time->tm_mday = bcd2val(dr, RTC_DR_DU_Pos, DR_D_MASK);
time->tm_hour = bcd2val(tr, RTC_TR_HU_Pos, TR_H_MASK);
time->tm_min = bcd2val(tr, RTC_TR_MNU_Pos, TR_M_MASK);
time->tm_sec = bcd2val(tr, RTC_TR_SU_Pos, TR_S_MASK);
return 0;
}
int rtc_set_alarm(struct tm *time, rtc_alarm_cb_t cb, void *arg)
{
/* normalize input */
rtc_tm_normalize(time);
rtc_unlock();
/* disable existing alarm (if enabled) */
rtc_clear_alarm();
/* save callback and argument */
isr_ctx.cb = cb;
isr_ctx.arg = arg;
/* set wakeup time */
RTC->ALRMAR = (val2bcd(time->tm_mday, RTC_ALRMAR_DU_Pos, ALRM_D_MASK) |
val2bcd(time->tm_hour, RTC_ALRMAR_HU_Pos, ALRM_H_MASK) |
val2bcd(time->tm_min, RTC_ALRMAR_MNU_Pos, ALRM_M_MASK) |
val2bcd(time->tm_sec, RTC_ALRMAR_SU_Pos, ALRM_S_MASK));
/* Enable Alarm A */
RTC->ISR &= ~(RTC_ISR_ALRAF);
RTC->CR |= (RTC_CR_ALRAE | RTC_CR_ALRAIE);
rtc_lock();
return 0;
}
int rtc_get_alarm(struct tm *time)
{
uint32_t dr = RTC->DR;
uint32_t alrm = RTC->ALRMAR;
time->tm_year = bcd2val(dr, RTC_DR_YU_Pos, DR_Y_MASK) + YEAR_OFFSET;
time->tm_mon = bcd2val(dr, RTC_DR_MU_Pos, DR_M_MASK) - 1;
time->tm_mday = bcd2val(alrm, RTC_ALRMAR_DU_Pos, ALRM_D_MASK);
time->tm_hour = bcd2val(alrm, RTC_ALRMAR_HU_Pos, ALRM_H_MASK);
time->tm_min = bcd2val(alrm, RTC_ALRMAR_MNU_Pos, ALRM_M_MASK);
time->tm_sec = bcd2val(alrm, RTC_ALRMAR_SU_Pos, ALRM_S_MASK);
return 0;
}
void rtc_clear_alarm(void)
{
RTC->CR &= ~(RTC_CR_ALRAE | RTC_CR_ALRAIE);
while (!(RTC->ISR & RTC_ISR_ALRAWF)) {}
isr_ctx.cb = NULL;
isr_ctx.arg = NULL;
}
void rtc_poweron(void)
{
stmclk_dbp_unlock();
EN_REG |= EN_BIT;
stmclk_dbp_lock();
}
void rtc_poweroff(void)
{
stmclk_dbp_unlock();
EN_REG &= ~EN_BIT;
stmclk_dbp_lock();
}
void ISR_NAME(void)
{
if (RTC->ISR & RTC_ISR_ALRAF) {
if (isr_ctx.cb != NULL) {
isr_ctx.cb(isr_ctx.arg);
}
RTC->ISR &= ~RTC_ISR_ALRAF;
}
EXTI->PR = EXTI_PR_BIT; /* only clear the associated bit */
cortexm_isr_end();
}
#endif /* !CPU_FAM_STM32F1 */

View File

@ -1,215 +0,0 @@
/*
* Copyright (C) 2017 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.
*/
/**
* @ingroup cpu_stm32_common
* @ingroup drivers_periph_rtt
* @{
*
* @file
* @brief RTT implementation using LPTIM1
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include "cpu.h"
#include "irq.h"
#include "periph/rtt.h"
#include "stmclk.h"
/* this driver is only valid for STM CPUs that provide LPTIMERs */
#if defined(LPTIM1)
/* figure out the used pre-scaler */
#if (RTT_FREQUENCY == 32768)
#define PRE (0)
#elif (RTT_FREQUENCY == 16384)
#define PRE (LPTIM_CFGR_PRESC_0)
#elif (RTT_FREQUENCY == 8192)
#define PRE (LPTIM_CFGR_PRESC_1)
#elif (RTT_FREQUENCY == 4096)
#define PRE (LPTIM_CFGR_PRESC_1 | LPTIM_CFGR_PRESC_0)
#elif (RTT_FREQUENCY == 2048)
#define PRE (LPTIM_CFGR_PRESC_2)
#elif (RTT_FREQUENCY == 1024)
#define PRE (LPTIM_CFGR_PRESC_2 | LPTIM_CFGR_PRESC_0)
#elif (RTT_FREQUENCY == 512)
#define PRE (LPTIM_CFGR_PRESC_2 | LPTIM_CFGR_PRESC_1)
#elif (RTT_FREQUENCY == 256)
#define PRE (LPTIM_CFGR_PRESC)
#else
#error "RTT config: RTT_FREQUENCY not configured or invalid for your board"
#endif
#if defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32F7)
#define CLOCK_SRC_REG RCC->DCKCFGR2
#define CLOCK_SRC_MASK RCC_DCKCFGR2_LPTIM1SEL
#if CLOCK_LSE
#define CLOCK_SRC_CFG (RCC_DCKCFGR2_LPTIM1SEL_1 | RCC_DCKCFGR2_LPTIM1SEL_0)
#else
#define CLOCK_SRC_CFG (RCC_DCKCFGR2_LPTIM1SEL_0)
#endif
#else
#define CLOCK_SRC_REG RCC->CCIPR
#define CLOCK_SRC_MASK RCC_CCIPR_LPTIM1SEL
#if CLOCK_LSE
#define CLOCK_SRC_CFG (RCC_CCIPR_LPTIM1SEL_1 | RCC_CCIPR_LPTIM1SEL_0)
#else
#define CLOCK_SRC_CFG (RCC_CCIPR_LPTIM1SEL_0)
#endif
#endif
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
#define IMR_REG IMR2
#define EXTI_IMR_BIT EXTI_IMR2_IM32
#elif defined(CPU_FAM_STM32L0)
#define IMR_REG IMR
#define EXTI_IMR_BIT EXTI_IMR_IM29
#else
#define IMR_REG IMR
#define FTSR_REG FTSR
#define RTSR_REG RTSR
#define PR_REG PR
#define EXTI_FTSR_BIT EXTI_FTSR_TR23
#define EXTI_RTSR_BIT EXTI_RTSR_TR23
#define EXTI_IMR_BIT EXTI_IMR_MR23
#define EXTI_PR_BIT EXTI_PR_PR23
#endif
/* allocate memory for overflow and alarm callbacks + args */
static rtt_cb_t ovf_cb = NULL;
static void *ovf_arg;
static rtt_cb_t to_cb = NULL;
static void *to_arg;
void rtt_init(void)
{
stmclk_enable_lfclk();
/* power on the selected LPTIMER */
rtt_poweron();
/* stop the timer and reset configuration */
LPTIM1->CR = 0;
/* select low speed clock (LSI or LSE) */
CLOCK_SRC_REG &= ~(CLOCK_SRC_MASK);
CLOCK_SRC_REG |= CLOCK_SRC_CFG;
/* set configuration: prescale factor and external clock (LSI or LSE) */
LPTIM1->CFGR = PRE;
/* enable overflow and compare interrupts */
LPTIM1->IER = (LPTIM_IER_ARRMIE | LPTIM_IER_CMPMIE);
/* configure the EXTI channel, as RTT interrupts are routed through it.
* Needs to be configured to trigger on rising edges. */
EXTI->IMR_REG |= EXTI_IMR_BIT;
#if !defined(CPU_FAM_STM32L4) && !defined(CPU_FAM_STM32L0) && \
!defined(CPU_FAM_STM32WB)
EXTI->FTSR_REG &= ~(EXTI_FTSR_BIT);
EXTI->RTSR_REG |= EXTI_RTSR_BIT;
EXTI->PR_REG = EXTI_PR_BIT;
#endif
NVIC_EnableIRQ(LPTIM1_IRQn);
/* enable timer */
LPTIM1->CR = LPTIM_CR_ENABLE;
/* set auto-reload value (timer needs to be enabled for this) */
LPTIM1->ICR = LPTIM_ICR_ARROKCF;
LPTIM1->ARR = RTT_MAX_VALUE;
while (!(LPTIM1->ISR & LPTIM_ISR_ARROK)) {}
/* start the timer */
LPTIM1->CR |= LPTIM_CR_CNTSTRT;
}
uint32_t rtt_get_counter(void)
{
uint32_t cnt;
do {
cnt = LPTIM1->CNT;
} while (cnt != LPTIM1->CNT);
return cnt;
}
void rtt_set_overflow_cb(rtt_cb_t cb, void *arg)
{
assert(cb);
unsigned is = irq_disable();
ovf_cb = cb;
ovf_arg = arg;
irq_restore(is);
}
void rtt_clear_overflow_cb(void)
{
ovf_cb = NULL;
}
void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg)
{
assert(cb && !(alarm & ~RTT_MAX_VALUE));
unsigned is = irq_disable();
LPTIM1->ICR = LPTIM_ICR_CMPOKCF;
to_cb = cb;
to_arg = arg;
LPTIM1->CMP = (uint16_t)alarm;
while (!(LPTIM1->ISR & LPTIM_ISR_CMPOK)) {}
irq_restore(is);
}
void rtt_clear_alarm(void)
{
to_cb = NULL;
}
void rtt_poweron(void)
{
#ifdef RCC_APB1ENR1_LPTIM1EN
periph_clk_en(APB1, RCC_APB1ENR1_LPTIM1EN);
#else
periph_clk_en(APB1, RCC_APB1ENR_LPTIM1EN);
#endif
}
void rtt_poweroff(void)
{
#ifdef RCC_APB1ENR1_LPTIM1EN
periph_clk_dis(APB1, RCC_APB1ENR1_LPTIM1EN);
#else
periph_clk_dis(APB1, RCC_APB1ENR_LPTIM1EN);
#endif
}
void isr_lptim1(void)
{
if (LPTIM1->ISR & LPTIM_ISR_CMPM) {
if (to_cb) {
/* 'consume' the callback (as it might be set again in the cb) */
rtt_cb_t tmp = to_cb;
to_cb = NULL;
tmp(to_arg);
}
}
if (LPTIM1->ISR & LPTIM_ISR_ARRM) {
if (ovf_cb) {
ovf_cb(ovf_arg);
}
}
LPTIM1->ICR = (LPTIM_ICR_ARRMCF | LPTIM_ICR_CMPMCF);
#if !defined(CPU_FAM_STM32L4) && !defined(CPU_FAM_STM32L0) && \
!defined(CPU_FAM_STM32WB)
EXTI->PR_REG = EXTI_PR_BIT; /* only clear the associated bit */
#endif
cortexm_isr_end();
}
#endif /* LPTIM1 */

View File

@ -1,300 +0,0 @@
/*
* Copyright (C) 2014 Hamburg University of Applied Sciences
* 2014-2017 Freie Universität Berlin
* 2016-2017 OTA keys S.A.
*
* 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 cpu_stm32_common
* @ingroup drivers_periph_spi
* @{
*
* @file
* @brief Low-level SPI driver implementation
*
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
* @author Fabian Nack <nack@inf.fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Vincent Dupont <vincent@otakeys.com>
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
*
* @}
*/
#include "cpu.h"
#include "mutex.h"
#include "assert.h"
#include "periph/spi.h"
#include "pm_layered.h"
/**
* @brief Number of bits to shift the BR value in the CR1 register
*/
#define BR_SHIFT (3U)
/**
* @brief Allocate one lock per SPI device
*/
static mutex_t locks[SPI_NUMOF];
static inline SPI_TypeDef *dev(spi_t bus)
{
return spi_config[bus].dev;
}
void spi_init(spi_t bus)
{
assert(bus < SPI_NUMOF);
/* initialize device lock */
mutex_init(&locks[bus]);
/* trigger pin initialization */
spi_init_pins(bus);
periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask);
/* reset configuration */
dev(bus)->CR1 = 0;
#ifdef SPI_I2SCFGR_I2SE
dev(bus)->I2SCFGR = 0;
#endif
/* configure SPI for 8-bit data width */
#ifdef SPI_CR2_FRXTH
dev(bus)->CR2 = (SPI_CR2_FRXTH | SPI_CR2_DS_0 | SPI_CR2_DS_1 | SPI_CR2_DS_2);
#else
dev(bus)->CR2 = 0;
#endif
periph_clk_dis(spi_config[bus].apbbus, spi_config[bus].rccmask);
}
void spi_init_pins(spi_t bus)
{
#ifdef CPU_FAM_STM32F1
gpio_init_af(spi_config[bus].sclk_pin, GPIO_AF_OUT_PP);
gpio_init_af(spi_config[bus].mosi_pin, GPIO_AF_OUT_PP);
gpio_init(spi_config[bus].miso_pin, GPIO_IN);
#else
gpio_init(spi_config[bus].mosi_pin, GPIO_OUT);
gpio_init(spi_config[bus].miso_pin, GPIO_IN);
gpio_init(spi_config[bus].sclk_pin, GPIO_OUT);
gpio_init_af(spi_config[bus].mosi_pin, spi_config[bus].mosi_af);
gpio_init_af(spi_config[bus].miso_pin, spi_config[bus].miso_af);
gpio_init_af(spi_config[bus].sclk_pin, spi_config[bus].sclk_af);
#endif
}
int spi_init_cs(spi_t bus, spi_cs_t cs)
{
if (bus >= SPI_NUMOF) {
return SPI_NODEV;
}
if (cs == SPI_CS_UNDEF ||
(((cs & SPI_HWCS_MASK) == SPI_HWCS_MASK) && (cs & ~(SPI_HWCS_MASK)))) {
return SPI_NOCS;
}
if (cs == SPI_HWCS_MASK) {
if (spi_config[bus].cs_pin == GPIO_UNDEF) {
return SPI_NOCS;
}
#ifdef CPU_FAM_STM32F1
gpio_init_af(spi_config[bus].cs_pin, GPIO_AF_OUT_PP);
#else
gpio_init(spi_config[bus].cs_pin, GPIO_OUT);
gpio_init_af(spi_config[bus].cs_pin, spi_config[bus].cs_af);
#endif
}
else {
gpio_init((gpio_t)cs, GPIO_OUT);
gpio_set((gpio_t)cs);
}
return SPI_OK;
}
#ifdef MODULE_PERIPH_SPI_GPIO_MODE
int spi_init_with_gpio_mode(spi_t bus, spi_gpio_mode_t mode)
{
assert(bus < SPI_NUMOF);
int ret = 0;
#ifdef CPU_FAM_STM32F1
/* This has no effect on STM32F1 */
return ret;
#else
ret += gpio_init(spi_config[bus].mosi_pin, mode.mosi);
ret += gpio_init(spi_config[bus].miso_pin, mode.miso);
ret += gpio_init(spi_config[bus].sclk_pin, mode.sclk);
gpio_init_af(spi_config[bus].mosi_pin, spi_config[bus].mosi_af);
gpio_init_af(spi_config[bus].miso_pin, spi_config[bus].miso_af);
gpio_init_af(spi_config[bus].sclk_pin, spi_config[bus].sclk_af);
return ret;
#endif
}
#endif
int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
{
/* lock bus */
mutex_lock(&locks[bus]);
#ifdef STM32_PM_STOP
/* block STOP mode */
pm_block(STM32_PM_STOP);
#endif
/* enable SPI device clock */
periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask);
/* enable device */
uint8_t br = spi_divtable[spi_config[bus].apbbus][clk];
dev(bus)->CR1 = ((br << BR_SHIFT) | mode | SPI_CR1_MSTR);
if (cs != SPI_HWCS_MASK) {
dev(bus)->CR1 |= (SPI_CR1_SSM | SPI_CR1_SSI);
}
else {
dev(bus)->CR2 |= (SPI_CR2_SSOE);
}
return SPI_OK;
}
void spi_release(spi_t bus)
{
/* disable device and release lock */
dev(bus)->CR1 = 0;
dev(bus)->CR2 &= ~(SPI_CR2_SSOE);
periph_clk_dis(spi_config[bus].apbbus, spi_config[bus].rccmask);
#ifdef STM32_PM_STOP
/* unblock STOP mode */
pm_unblock(STM32_PM_STOP);
#endif
mutex_unlock(&locks[bus]);
}
static inline void _wait_for_end(spi_t bus)
{
/* make sure the transfer is completed before continuing, see reference
* manual(s) -> section 'Disabling the SPI' */
while (!(dev(bus)->SR & SPI_SR_TXE)) {}
while (dev(bus)->SR & SPI_SR_BSY) {}
}
#ifdef MODULE_PERIPH_DMA
static void _transfer_dma(spi_t bus, const void *out, void *in, size_t len)
{
uint8_t tmp = 0;
dma_acquire(spi_config[bus].tx_dma);
dma_acquire(spi_config[bus].rx_dma);
if (!out) {
dma_configure(spi_config[bus].tx_dma, spi_config[bus].tx_dma_chan, &tmp,
&(dev(bus)->DR), len, DMA_MEM_TO_PERIPH, 0);
}
else {
dma_configure(spi_config[bus].tx_dma, spi_config[bus].tx_dma_chan, out,
&(dev(bus)->DR), len, DMA_MEM_TO_PERIPH, DMA_INC_SRC_ADDR);
}
if (!in) {
dma_configure(spi_config[bus].rx_dma, spi_config[bus].rx_dma_chan,
&(dev(bus)->DR), &tmp, len, DMA_PERIPH_TO_MEM, 0);
}
else {
dma_configure(spi_config[bus].rx_dma, spi_config[bus].rx_dma_chan,
&(dev(bus)->DR), in, len, DMA_PERIPH_TO_MEM, DMA_INC_DST_ADDR);
}
dev(bus)->CR2 |= SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN;
dma_start(spi_config[bus].rx_dma);
dma_start(spi_config[bus].tx_dma);
dma_wait(spi_config[bus].rx_dma);
dma_wait(spi_config[bus].tx_dma);
dev(bus)->CR2 &= ~(SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN);
dma_stop(spi_config[bus].tx_dma);
dma_stop(spi_config[bus].rx_dma);
dma_release(spi_config[bus].tx_dma);
dma_release(spi_config[bus].rx_dma);
_wait_for_end(bus);
}
#endif
static void _transfer_no_dma(spi_t bus, const void *out, void *in, size_t len)
{
const uint8_t *outbuf = out;
uint8_t *inbuf = in;
/* we need to recast the data register to uint_8 to force 8-bit access */
volatile uint8_t *DR = (volatile uint8_t*)&(dev(bus)->DR);
/* transfer data, use shortpath if only sending data */
if (!inbuf) {
for (size_t i = 0; i < len; i++) {
while (!(dev(bus)->SR & SPI_SR_TXE));
*DR = outbuf[i];
}
/* wait until everything is finished and empty the receive buffer */
while (!(dev(bus)->SR & SPI_SR_TXE)) {}
while (dev(bus)->SR & SPI_SR_BSY) {}
while (dev(bus)->SR & SPI_SR_RXNE) {
dev(bus)->DR; /* we might just read 2 bytes at once here */
}
}
else if (!outbuf) {
for (size_t i = 0; i < len; i++) {
while (!(dev(bus)->SR & SPI_SR_TXE));
*DR = 0;
while (!(dev(bus)->SR & SPI_SR_RXNE));
inbuf[i] = *DR;
}
}
else {
for (size_t i = 0; i < len; i++) {
while (!(dev(bus)->SR & SPI_SR_TXE));
*DR = outbuf[i];
while (!(dev(bus)->SR & SPI_SR_RXNE));
inbuf[i] = *DR;
}
}
_wait_for_end(bus);
}
void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
const void *out, void *in, size_t len)
{
/* make sure at least one input or one output buffer is given */
assert(out || in);
/* active the given chip select line */
dev(bus)->CR1 |= (SPI_CR1_SPE); /* this pulls the HW CS line low */
if ((cs != SPI_HWCS_MASK) && (cs != SPI_CS_UNDEF)) {
gpio_clear((gpio_t)cs);
}
#ifdef MODULE_PERIPH_DMA
if (spi_config[bus].tx_dma != DMA_STREAM_UNDEF
&& spi_config[bus].rx_dma != DMA_STREAM_UNDEF) {
_transfer_dma(bus, out, in, len);
}
else {
#endif
_transfer_no_dma(bus, out, in, len);
#ifdef MODULE_PERIPH_DMA
}
#endif
/* release the chip select if not specified differently */
if ((!cont) && (cs != SPI_CS_UNDEF)) {
dev(bus)->CR1 &= ~(SPI_CR1_SPE); /* pull HW CS line high */
if (cs != SPI_HWCS_MASK) {
gpio_set((gpio_t)cs);
}
}
}

View File

@ -1,155 +0,0 @@
/*
* Copyright (C) 2014-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.
*/
/**
* @ingroup cpu_stm32_common
* @ingroup drivers_periph_timer
* @{
*
* @file
* @brief Low-level timer driver implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
*
* @}
*/
#include "cpu.h"
#include "periph/timer.h"
/**
* @brief Interrupt context for each configured timer
*/
static timer_isr_ctx_t isr_ctx[TIMER_NUMOF];
/**
* @brief Get the timer device
*/
static inline TIM_TypeDef *dev(tim_t tim)
{
return timer_config[tim].dev;
}
int timer_init(tim_t tim, unsigned long freq, timer_cb_t cb, void *arg)
{
/* check if device is valid */
if (tim >= TIMER_NUMOF) {
return -1;
}
/* remember the interrupt context */
isr_ctx[tim].cb = cb;
isr_ctx[tim].arg = arg;
/* enable the peripheral clock */
periph_clk_en(timer_config[tim].bus, timer_config[tim].rcc_mask);
/* configure the timer as upcounter in continuous mode */
dev(tim)->CR1 = 0;
dev(tim)->CR2 = 0;
dev(tim)->ARR = timer_config[tim].max;
/* set prescaler */
dev(tim)->PSC = ((periph_timer_clk(timer_config[tim].bus) / freq) - 1);
/* generate an update event to apply our configuration */
dev(tim)->EGR = TIM_EGR_UG;
/* enable the timer's interrupt */
NVIC_EnableIRQ(timer_config[tim].irqn);
/* reset the counter and start the timer */
timer_start(tim);
return 0;
}
int timer_set_absolute(tim_t tim, int channel, unsigned int value)
{
if (channel >= (int)TIMER_CHAN) {
return -1;
}
dev(tim)->CCR[channel] = (value & timer_config[tim].max);
dev(tim)->SR &= ~(TIM_SR_CC1IF << channel);
dev(tim)->DIER |= (TIM_DIER_CC1IE << channel);
return 0;
}
int timer_clear(tim_t tim, int channel)
{
if (channel >= (int)TIMER_CHAN) {
return -1;
}
dev(tim)->DIER &= ~(TIM_DIER_CC1IE << channel);
return 0;
}
unsigned int timer_read(tim_t tim)
{
return (unsigned int)dev(tim)->CNT;
}
void timer_start(tim_t tim)
{
dev(tim)->CR1 |= TIM_CR1_CEN;
}
void timer_stop(tim_t tim)
{
dev(tim)->CR1 &= ~(TIM_CR1_CEN);
}
static inline void irq_handler(tim_t tim)
{
uint32_t status = (dev(tim)->SR & dev(tim)->DIER);
for (unsigned int i = 0; i < TIMER_CHAN; i++) {
if (status & (TIM_SR_CC1IF << i)) {
dev(tim)->DIER &= ~(TIM_DIER_CC1IE << i);
isr_ctx[tim].cb(isr_ctx[tim].arg, i);
}
}
cortexm_isr_end();
}
#ifdef TIMER_0_ISR
void TIMER_0_ISR(void)
{
irq_handler(0);
}
#endif
#ifdef TIMER_1_ISR
void TIMER_1_ISR(void)
{
irq_handler(1);
}
#endif
#ifdef TIMER_2_ISR
void TIMER_2_ISR(void)
{
irq_handler(2);
}
#endif
#ifdef TIMER_3_ISR
void TIMER_3_ISR(void)
{
irq_handler(3);
}
#endif
#ifdef TIMER_4_ISR
void TIMER_4_ISR(void)
{
irq_handler(4);
}
#endif

View File

@ -1,476 +0,0 @@
/*
* Copyright (C) 2014-2017 Freie Universität Berlin
* Copyright (C) 2016 OTA keys
* Copyright (C) 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 cpu_stm32_common
* @ingroup drivers_periph_uart
* @{
*
* @file
* @brief Low-level UART driver implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
* @author Fabian Nack <nack@inf.fu-berlin.de>
* @author Hermann Lelong <hermann@otakeys.com>
* @author Toon Stegen <toon.stegen@altran.com>
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
*
* @}
*/
#include "cpu.h"
#include "sched.h"
#include "thread.h"
#include "assert.h"
#include "periph/uart.h"
#include "periph/gpio.h"
#include "pm_layered.h"
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) || \
defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4) || \
defined(CPU_FAM_STM32WB) || defined(CPU_FAM_STM32F7)
#define ISR_REG ISR
#define ISR_TXE USART_ISR_TXE
#define ISR_TC USART_ISR_TC
#define TDR_REG TDR
#else
#define ISR_REG SR
#define ISR_TXE USART_SR_TXE
#define ISR_TC USART_SR_TC
#define TDR_REG DR
#endif
#define RXENABLE (USART_CR1_RE | USART_CR1_RXNEIE)
/**
* @brief Allocate memory to store the callback functions
*
* Extend standard uart_isr_ctx_t with data_mask field. This is needed
* in order to mask parity bit.
*/
static struct {
uart_rx_cb_t rx_cb; /**< data received interrupt callback */
void *arg; /**< argument to both callback routines */
uint8_t data_mask; /**< mask applied to the data register */
} isr_ctx[UART_NUMOF];
static inline USART_TypeDef *dev(uart_t uart)
{
return uart_config[uart].dev;
}
static inline void uart_init_usart(uart_t uart, uint32_t baudrate);
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L4) || \
defined(CPU_FAM_STM32WB)
#ifdef MODULE_PERIPH_LPUART
static inline void uart_init_lpuart(uart_t uart, uint32_t baudrate);
#endif
#endif
#ifdef MODULE_PERIPH_UART_HW_FC
static inline void uart_init_rts_pin(uart_t uart)
{
if (uart_config[uart].rts_pin != GPIO_UNDEF) {
gpio_init(uart_config[uart].rts_pin, GPIO_OUT);
#ifdef CPU_FAM_STM32F1
gpio_init_af(uart_config[uart].rts_pin, GPIO_AF_OUT_PP);
#else
gpio_init_af(uart_config[uart].rts_pin, uart_config[uart].rts_af);
#endif
}
}
static inline void uart_init_cts_pin(uart_t uart)
{
if (uart_config[uart].cts_pin != GPIO_UNDEF) {
gpio_init(uart_config[uart].cts_pin, GPIO_IN);
#ifndef CPU_FAM_STM32F1
gpio_init_af(uart_config[uart].cts_pin, uart_config[uart].cts_af);
#endif
}
}
#endif
static inline void uart_init_pins(uart_t uart, uart_rx_cb_t rx_cb)
{
/* configure TX pin */
gpio_init(uart_config[uart].tx_pin, GPIO_OUT);
/* set TX pin high to avoid garbage during further initialization */
gpio_set(uart_config[uart].tx_pin);
#ifdef CPU_FAM_STM32F1
gpio_init_af(uart_config[uart].tx_pin, GPIO_AF_OUT_PP);
#else
gpio_init_af(uart_config[uart].tx_pin, uart_config[uart].tx_af);
#endif
/* configure RX pin */
if (rx_cb) {
gpio_init(uart_config[uart].rx_pin, GPIO_IN_PU);
#ifndef CPU_FAM_STM32F1
gpio_init_af(uart_config[uart].rx_pin, uart_config[uart].rx_af);
#endif
}
#ifdef MODULE_PERIPH_UART_HW_FC
uart_init_cts_pin(uart);
uart_init_rts_pin(uart);
#endif
}
static inline void uart_enable_clock(uart_t uart)
{
#ifdef STM32_PM_STOP
if (isr_ctx[uart].rx_cb) {
pm_block(STM32_PM_STOP);
}
#endif
periph_clk_en(uart_config[uart].bus, uart_config[uart].rcc_mask);
}
static inline void uart_disable_clock(uart_t uart)
{
periph_clk_dis(uart_config[uart].bus, uart_config[uart].rcc_mask);
#ifdef STM32_PM_STOP
if (isr_ctx[uart].rx_cb) {
pm_unblock(STM32_PM_STOP);
}
#endif
}
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
{
assert(uart < UART_NUMOF);
/* save ISR context */
isr_ctx[uart].rx_cb = rx_cb;
isr_ctx[uart].arg = arg;
isr_ctx[uart].data_mask = 0xFF;
uart_init_pins(uart, rx_cb);
uart_enable_clock(uart);
/* reset UART configuration -> defaults to 8N1 mode */
dev(uart)->CR1 = 0;
dev(uart)->CR2 = 0;
dev(uart)->CR3 = 0;
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L4) || \
defined(CPU_FAM_STM32WB)
switch (uart_config[uart].type) {
case STM32_USART:
uart_init_usart(uart, baudrate);
break;
#ifdef MODULE_PERIPH_LPUART
case STM32_LPUART:
uart_init_lpuart(uart, baudrate);
break;
#endif
default:
return UART_NODEV;
}
#else
uart_init_usart(uart, baudrate);
#endif
/* enable RX interrupt if applicable */
if (rx_cb) {
NVIC_EnableIRQ(uart_config[uart].irqn);
dev(uart)->CR1 = (USART_CR1_UE | USART_CR1_TE | RXENABLE);
}
else {
dev(uart)->CR1 = (USART_CR1_UE | USART_CR1_TE);
}
#ifdef MODULE_PERIPH_UART_HW_FC
if (uart_config[uart].cts_pin != GPIO_UNDEF) {
dev(uart)->CR3 |= USART_CR3_CTSE;
}
if (uart_config[uart].rts_pin != GPIO_UNDEF) {
dev(uart)->CR3 |= USART_CR3_RTSE;
}
#endif
return UART_OK;
}
#ifdef MODULE_PERIPH_UART_MODECFG
int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity,
uart_stop_bits_t stop_bits)
{
assert(uart < UART_NUMOF);
isr_ctx[uart].data_mask = 0xFF;
if (parity) {
switch (data_bits) {
case UART_DATA_BITS_6:
data_bits = UART_DATA_BITS_7;
isr_ctx[uart].data_mask = 0x3F;
break;
case UART_DATA_BITS_7:
data_bits = UART_DATA_BITS_8;
isr_ctx[uart].data_mask = 0x7F;
break;
case UART_DATA_BITS_8:
#ifdef USART_CR1_M0
data_bits = USART_CR1_M0;
#else
data_bits = USART_CR1_M;
#endif
break;
default:
return UART_NOMODE;
}
}
if ((data_bits & UART_INVALID_MODE) || (parity & UART_INVALID_MODE)) {
return UART_NOMODE;
}
#ifdef USART_CR1_M1
if (!(dev(uart)->ISR & USART_ISR_TC)) {
return UART_INTERR;
}
dev(uart)->CR1 &= ~(USART_CR1_UE | USART_CR1_TE);
#endif
dev(uart)->CR2 &= ~USART_CR2_STOP;
dev(uart)->CR1 &= ~(USART_CR1_PS | USART_CR1_PCE | USART_CR1_M);
dev(uart)->CR2 |= stop_bits;
dev(uart)->CR1 |= (USART_CR1_UE | USART_CR1_TE | data_bits | parity);
return UART_OK;
}
#endif /* MODULE_PERIPH_UART_MODECFG */
static inline void uart_init_usart(uart_t uart, uint32_t baudrate)
{
uint16_t mantissa;
uint8_t fraction;
uint32_t clk;
/* calculate and apply baudrate */
clk = periph_apb_clk(uart_config[uart].bus) / baudrate;
mantissa = (uint16_t)(clk / 16);
fraction = (uint8_t)(clk - (mantissa * 16));
dev(uart)->BRR = ((mantissa & 0x0fff) << 4) | (fraction & 0x0f);
}
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L4) || \
defined(CPU_FAM_STM32WB)
#ifdef MODULE_PERIPH_LPUART
static inline void uart_init_lpuart(uart_t uart, uint32_t baudrate)
{
uint32_t clk;
switch (uart_config[uart].clk_src) {
case 0:
clk = periph_apb_clk(uart_config[uart].bus);
break;
case RCC_CCIPR_LPUART1SEL_0:
clk = CLOCK_CORECLOCK;
break;
case (RCC_CCIPR_LPUART1SEL_0 | RCC_CCIPR_LPUART1SEL_1):
clk = 32768;
break;
default: /* HSI is not supported */
return;
}
RCC->CCIPR |= uart_config[uart].clk_src;
/* LSE can only be used with baudrate <= 9600 */
if ( (clk < (3 * baudrate)) || (clk > (4096 * baudrate))) {
return;
}
/* LPUARTDIV = f_clk * 256 / baudrate */
uint32_t brr = (uint32_t)(((uint64_t)clk << 8) / baudrate);
dev(uart)->BRR = brr;
}
#endif /* MODULE_PERIPH_LPUART */
#endif /* STM32L0 || STM32L4 || STM32WB */
static inline void send_byte(uart_t uart, uint8_t byte)
{
while (!(dev(uart)->ISR_REG & ISR_TXE)) {}
dev(uart)->TDR_REG = byte;
}
static inline void wait_for_tx_complete(uart_t uart)
{
while (!(dev(uart)->ISR_REG & ISR_TC)) {}
}
void uart_write(uart_t uart, const uint8_t *data, size_t len)
{
assert(uart < UART_NUMOF);
#if DEVELHELP
/* If tx is not enabled don't try to send */
if (!(dev(uart)->CR1 & USART_CR1_TE)) {
return;
}
#endif
#ifdef MODULE_PERIPH_DMA
if (!len) {
return;
}
if (uart_config[uart].dma != DMA_STREAM_UNDEF) {
if (irq_is_in()) {
uint16_t todo = 0;
if (dev(uart)->CR3 & USART_CR3_DMAT) {
/* DMA transfer for UART on-going */
todo = dma_suspend(uart_config[uart].dma);
}
if (todo) {
dma_stop(uart_config[uart].dma);
dev(uart)->CR3 &= ~USART_CR3_DMAT;
}
for (unsigned i = 0; i < len; i++) {
send_byte(uart, data[i]);
}
if (todo > 0) {
wait_for_tx_complete(uart);
dev(uart)->CR3 |= USART_CR3_DMAT;
dma_resume(uart_config[uart].dma, todo);
}
}
else {
dma_acquire(uart_config[uart].dma);
dev(uart)->CR3 |= USART_CR3_DMAT;
dma_transfer(uart_config[uart].dma, uart_config[uart].dma_chan, data,
(void *)&dev(uart)->TDR_REG, len, DMA_MEM_TO_PERIPH, DMA_INC_SRC_ADDR);
/* make sure the function is synchronous by waiting for the transfer to
* finish */
wait_for_tx_complete(uart);
dev(uart)->CR3 &= ~USART_CR3_DMAT;
dma_release(uart_config[uart].dma);
}
return;
}
#endif
for (size_t i = 0; i < len; i++) {
send_byte(uart, data[i]);
}
/* make sure the function is synchronous by waiting for the transfer to
* finish */
wait_for_tx_complete(uart);
}
void uart_poweron(uart_t uart)
{
assert(uart < UART_NUMOF);
uart_enable_clock(uart);
dev(uart)->CR1 |= (USART_CR1_UE);
#ifdef MODULE_PERIPH_UART_HW_FC
/* STM32F4 errata 2.10.9: nRTS is active while RE or UE = 0
* we should only configure nRTS pin after setting UE */
uart_init_rts_pin(uart);
#endif
}
void uart_poweroff(uart_t uart)
{
assert(uart < UART_NUMOF);
#ifdef MODULE_PERIPH_UART_HW_FC
/* the uart peripheral does not put RTS high from hardware when
* UE flag is cleared, so we need to do this manually */
if (uart_config[uart].rts_pin != GPIO_UNDEF) {
gpio_init(uart_config[uart].rts_pin, GPIO_OUT);
gpio_set(uart_config[uart].rts_pin);
}
#endif
dev(uart)->CR1 &= ~(USART_CR1_UE);
uart_disable_clock(uart);
}
static inline void irq_handler(uart_t uart)
{
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32L0) || \
defined(CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L4) || \
defined(CPU_FAM_STM32F7) || defined(CPU_FAM_STM32WB)
uint32_t status = dev(uart)->ISR;
if (status & USART_ISR_RXNE) {
isr_ctx[uart].rx_cb(isr_ctx[uart].arg,
(uint8_t)dev(uart)->RDR & isr_ctx[uart].data_mask);
}
if (status & USART_ISR_ORE) {
dev(uart)->ICR |= USART_ICR_ORECF; /* simply clear flag on overrun */
}
#else
uint32_t status = dev(uart)->SR;
if (status & USART_SR_RXNE) {
isr_ctx[uart].rx_cb(isr_ctx[uart].arg,
(uint8_t)dev(uart)->DR & isr_ctx[uart].data_mask);
}
if (status & USART_SR_ORE) {
/* ORE is cleared by reading SR and DR sequentially */
dev(uart)->DR;
}
#endif
cortexm_isr_end();
}
#ifdef UART_0_ISR
void UART_0_ISR(void)
{
irq_handler(UART_DEV(0));
}
#endif
#ifdef UART_1_ISR
void UART_1_ISR(void)
{
irq_handler(UART_DEV(1));
}
#endif
#ifdef UART_2_ISR
void UART_2_ISR(void)
{
irq_handler(UART_DEV(2));
}
#endif
#ifdef UART_3_ISR
void UART_3_ISR(void)
{
irq_handler(UART_DEV(3));
}
#endif
#ifdef UART_4_ISR
void UART_4_ISR(void)
{
irq_handler(UART_DEV(4));
}
#endif
#ifdef UART_5_ISR
void UART_5_ISR(void)
{
irq_handler(UART_DEV(5));
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,146 +0,0 @@
/*
* Copyright (C) 2019 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 cpu_stm32_common
* @ingroup drivers_periph_wdt
*
* @brief
*
* @{
*
* @file wdt.c
* @brief Independent Watchdog timer for STM32L platforms
*
* @author Francisco Molina <francois-xavier.molina@inria.fr>
*/
#include <stdlib.h>
#include <assert.h>
#include "cpu.h"
#include "timex.h"
#include "periph_cpu.h"
#include "periph/wdt.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_RELOAD (4096U)
#define MAX_PRESCALER (6U)
#define IWDG_STEP_MS ((4U * US_PER_MS * MAX_RELOAD) / CLOCK_LSI)
#define IWDG_KR_KEY_RELOAD ((uint16_t)0xAAAA)
#define IWDG_KR_KEY_ENABLE ((uint16_t)0xCCCC)
#define IWDG_UNLOCK ((uint16_t)0x5555)
#define IWDG_LOCK ((uint16_t)0x0000)
#if ENABLE_DEBUG
/* wdt_time (us) = LSI(us) x 4 x 2^PRE x RELOAD */
static inline uint32_t _wdt_time(uint8_t pre, uint16_t rel)
{
return (uint32_t)(((uint64_t) US_PER_SEC * 4 * (1 << pre) * rel ) / CLOCK_LSI);
}
#endif
static inline void _iwdt_unlock(void)
{
IWDG->KR = IWDG_UNLOCK;
}
static inline void _iwdt_lock(void)
{
IWDG->KR = IWDG_LOCK;
}
static void _set_prescaler(uint8_t prescaler)
{
assert(prescaler <= MAX_PRESCALER);
_iwdt_unlock();
IWDG->PR = prescaler;
_iwdt_lock();
}
static void _set_reload(uint16_t reload)
{
assert(reload <= IWDG_RLR_RL);
_iwdt_unlock();
IWDG->RLR = reload;
_iwdt_lock();
}
static uint8_t _find_prescaler(uint32_t rst_time)
{
/* Divide by the range to get power of 2 of the prescaler */
uint8_t pre = 32U - __builtin_clz(rst_time / IWDG_STEP_MS);
DEBUG("[wdt]: prescaler value %d\n", pre);
return pre;
}
static uint16_t _find_reload_value(uint8_t pre, uint32_t rst_time)
{
/* Calculate best reload value = rst_time / LSI(ms) x 4 x 2^PRE */
uint16_t rel = (uint16_t)((rst_time * CLOCK_LSI) / \
((uint32_t) (US_PER_MS * 4 * (1 << pre))));
DEBUG("[wdt]: reload value %d\n", rel);
return rel;
}
void wdt_start(void)
{
IWDG->KR = IWDG_KR_KEY_ENABLE;
}
#ifdef CPU_FAM_STM32L4
void wdt_init(void)
{
FLASH->OPTR |= ~(FLASH_OPTR_IWDG_STOP || FLASH_OPTR_IWDG_STDBY);
}
#endif
void wdt_kick(void)
{
IWDG->KR = IWDG_KR_KEY_RELOAD;
}
void wdt_setup_reboot(uint32_t min_time, uint32_t max_time)
{
(void) min_time;
/* Windowed wdt not supported */
assert(min_time == 0);
/* Check reset time limit */
assert((max_time > NWDT_TIME_LOWER_LIMIT) || \
(max_time < NWDT_TIME_UPPER_LIMIT));
uint8_t pre = _find_prescaler(max_time);
uint16_t rel = _find_reload_value(pre, max_time);
/* Set watchdog prescaler and reload value */
_set_prescaler(pre);
_set_reload(rel);
#if ENABLE_DEBUG
DEBUG("[wdt]: reset time %lu [us]\n", _wdt_time(pre, rel));
#endif
/* Refresh wdt counter */
wdt_kick();
}
#ifdef __cplusplus
}
#endif

View File

@ -1,343 +0,0 @@
# Set the common memory addresses for stm32 MCU family
ROM_START_ADDR ?= 0x08000000
RAM_START_ADDR ?= 0x20000000
# The next block takes care of setting the rigth lengths of RAM and ROM
# for the stm32 family. Most of the CPUs should have been taken into
# account here, so no need to assign the lengths per model.
STM32_INFO := $(shell printf '%s' '$(CPU_MODEL)' | tr 'a-z' 'A-Z' | sed -E -e 's/^STM32(F|L|W)(0|1|2|3|4|7|B)([A-Z0-9])([0-9])(.)(.)(_A)?/\1 \2 \2\3\4 \3 \4 \5 \6 \7/')
STM32_TYPE := $(word 1, $(STM32_INFO))
STM32_FAMILY := $(word 2, $(STM32_INFO))
STM32_MODEL := $(word 3, $(STM32_INFO))
STM32_MODEL2 := $(word 4, $(STM32_INFO))
STM32_MODEL3 := $(word 5, $(STM32_INFO))
STM32_PINCOUNT := $(word 6, $(STM32_INFO))
STM32_ROMSIZE := $(word 7, $(STM32_INFO))
STM32_RAMMOD := $(word 8, $(STM32_INFO))
ifeq ($(STM32_TYPE), F)
ifeq ($(STM32_FAMILY), 0)
ifeq ($(STM32_MODEL2), 3)
ifeq ($(STM32_MODEL3), 0)
ifneq (, $(filter $(STM32_ROMSIZE), 4 6))
RAM_LEN = 4K
else ifeq ($(STM32_ROMSIZE), 8)
RAM_LEN = 8K
else ifeq ($(STM32_ROMSIZE), C)
RAM_LEN = 32K
endif
else ifneq (, $(filter $(STM32_MODEL3), 1 8))
RAM_LEN = 4K
endif
else ifeq ($(STM32_MODEL2), 4)
RAM_LEN = 6K
else ifeq ($(STM32_MODEL2), 5)
RAM_LEN = 8K
else ifeq ($(STM32_MODEL2), 7)
ifeq ($(STM32_MODEL3), 0)
ifeq ($(STM32_ROMSIZE), 6)
RAM_LEN = 6K
else ifeq ($(STM32_ROMSIZE), B)
RAM_LEN = 16K
endif
else ifneq (, $(filter $(STM32_MODEL3), 1 2 8))
RAM_LEN = 16K
endif
else ifeq ($(STM32_MODEL2), 9)
RAM_LEN = 32K
endif
else ifeq ($(STM32_FAMILY), 1)
ifeq ($(STM32_MODEL2), 0)
ifeq ($(STM32_MODEL3), 0)
ifneq (, $(filter $(STM32_ROMSIZE), 4 6))
RAM_LEN = 4K
else ifneq (, $(filter $(STM32_ROMSIZE), 8 B))
RAM_LEN = 8K
else ifeq ($(STM32_ROMSIZE), C)
RAM_LEN = 24K
else ifneq (, $(filter $(STM32_ROMSIZE), E D))
RAM_LEN = 32K
endif
else ifneq (, $(filter $(STM32_MODEL3), 1 2))
ifeq ($(STM32_ROMSIZE), 4)
RAM_LEN = 4K
else ifeq ($(STM32_ROMSIZE), 6)
RAM_LEN = 6K
else ifeq ($(STM32_ROMSIZE), 8)
RAM_LEN = 10K
else ifeq ($(STM32_ROMSIZE), B)
RAM_LEN = 16K
else ifeq ($(STM32_ROMSIZE), C)
RAM_LEN = 32K
else ifneq (, $(filter $(STM32_ROMSIZE), D E))
RAM_LEN = 48K
else ifneq (, $(filter $(STM32_ROMSIZE), F G))
RAM_LEN = 80K
endif
else ifeq ($(STM32_MODEL3), 3)
ifeq ($(STM32_ROMSIZE), 4)
RAM_LEN = 6K
else ifeq ($(STM32_ROMSIZE), 6)
RAM_LEN = 10K
else ifneq (, $(filter $(STM32_ROMSIZE), 8 B))
RAM_LEN = 20K
else ifneq (, $(filter $(STM32_ROMSIZE), C))
RAM_LEN = 48K
else ifneq (, $(filter $(STM32_ROMSIZE), D E))
RAM_LEN = 64K
else ifneq (, $(filter $(STM32_ROMSIZE), F G))
RAM_LEN = 96K
endif
else ifneq (, $(filter $(STM32_MODEL), 105 107))
RAM_LEN = 64K
endif
endif
else ifeq ($(STM32_FAMILY), 2)
ifeq ($(STM32_MODEL3), 5)
ifeq ($(STM32_ROMSIZE), B)
RAM_LEN = 64K
else ifeq ($(STM32_ROMSIZE), C)
RAM_LEN = 96K
else ifeq (, $(filter $(STM32_ROMSIZE), E F G))
RAM_LEN = 128K
endif
else ifeq ($(STM32_MODEL3), 7)
RAM_LEN = 128K
endif
else ifeq ($(STM32_FAMILY), 3)
ifeq ($(STM32_MODEL), 301)
RAM_LEN = 16K
else ifeq ($(STM32_MODEL), 302)
ifeq ($(STM32_ROMSIZE), 6)
RAM_LEN = 32K
else ifeq ($(STM32_ROMSIZE), 8)
RAM_LEN = 64K
else ifeq ($(STM32_ROMSIZE), B)
RAM_LEN = 128K
else ifeq ($(STM32_ROMSIZE), C)
RAM_LEN = 256K
else ifeq ($(STM32_ROMSIZE), D)
RAM_LEN = 384K
else ifeq ($(STM32_ROMSIZE), E)
RAM_LEN = 512K
endif
else ifeq ($(STM32_MODEL), 303)
ifneq (, $(filter $(STM32_ROMSIZE), 6 8))
RAM_LEN = 12K
CCMRAM_LEN = 4K
else ifeq ($(STM32_ROMSIZE), B)
RAM_LEN = 40K
CCMRAM_LEN = 8K
else ifeq ($(STM32_ROMSIZE), C)
RAM_LEN = 40K
CCMRAM_LEN = 8K
else ifneq (, $(filter $(STM32_ROMSIZE), D E))
RAM_LEN = 64K
CCMRAM_LEN = 16K
endif
else ifeq ($(STM32_MODEL3), 4)
RAM_LEN = 12K
CCMRAM_LEN = 4K
else ifeq ($(STM32_MODEL), 373)
RAM_LEN = 32K
else ifeq ($(STM32_MODEL3), 8)
ifneq (, $(filter $(STM32_MODEL2), 1 2))
RAM_LEN = 16K
ifeq ($(STM32_MODEL2), 1)
CCMRAM_LEN = 4K
endif
else ifeq ($(STM32_MODEL2), 5)
RAM_LEN = 48K
CCMRAM_LEN = 8K
else ifeq ($(STM32_MODEL2), 7)
RAM_LEN = 32K
else ifeq ($(STM32_MODEL2), 9)
RAM_LEN = 80K
CCMRAM_LEN = 16K
endif
endif
else ifeq ($(STM32_FAMILY), 4)
ifeq ($(STM32_MODEL), 401)
ifneq (, $(filter $(STM32_ROMSIZE), B C))
RAM_LEN = 64K
else ifneq (, $(filter $(STM32_ROMSIZE), D E))
RAM_LEN = 96K
endif
else ifneq (, $(filter $(STM32_MODEL), 405 407))
RAM_LEN = 192K
else ifeq ($(STM32_MODEL), 410)
RAM_LEN = 32K
else ifneq (, $(filter $(STM32_MODEL), 411 446))
RAM_LEN = 128K
else ifneq (, $(filter $(STM32_MODEL), 412 427 429 437 439))
RAM_LEN = 256K
else ifneq (, $(filter $(STM32_MODEL), 413 423))
RAM_LEN = 320K
else ifneq (, $(filter $(STM32_MODEL), 415 417))
RAM_LEN = 192K
else ifneq (, $(filter $(STM32_MODEL), 469 479))
RAM_LEN = 384K
endif
ifneq (, $(filter $(STM32_MODEL3), 5 7 9))
CCMRAM_LEN = 64K
endif
else ifeq ($(STM32_FAMILY),7)
ifneq (, $(filter $(STM32_MODEL2), 2 3))
RAM_LEN = 256K
else ifneq (, $(filter $(STM32_MODEL2), 4 5))
RAM_LEN = 320K
else ifneq (, $(filter $(STM32_MODEL2), 6 7))
RAM_LEN = 512K
endif
endif
else ifeq ($(STM32_TYPE), L)
ifeq ($(STM32_FAMILY), 0)
ifeq ($(STM32_MODEL2), 1)
RAM_LEN = 2K
ifeq ($(STM32_MODEL3), 0)
ifeq ($(STM32_ROMSIZE), 6)
RAM_LEN = 8K
endif
endif
else ifneq (, $(filter $(STM32_MODEL2), 2))
RAM_LEN = 2K
else ifneq (, $(filter $(STM32_MODEL2), 3 4 5 6))
RAM_LEN = 8K
else ifneq (, $(filter $(STM32_MODEL2), 7 8))
RAM_LEN = 20K
endif
else ifeq ($(STM32_FAMILY), 1)
ifeq ($(STM32_MODEL), 100)
ifeq ($(STM32_ROMSIZE), 6)
RAM_LEN = 4K
else ifeq ($(STM32_ROMSIZE), 8)
RAM_LEN = 8K
else ifeq ($(STM32_ROMSIZE)$(STM32_RAMMOD), B)
RAM_LEN = 10K
else ifneq (, $(filter $(STM32_ROMSIZE)$(STM32_RAMMOD), B_A C))
RAM_LEN = 16K
endif
else ifneq (, $(filter $(STM32_MODEL), 151 152))
ifneq (, $(filter $(STM32_PINCOUNT), C Q U V Z))
ifneq (, $(filter $(STM32_ROMSIZE)$(STM32_RAMMOD), 6 8))
RAM_LEN = 10K
else ifneq (, $(filter $(STM32_ROMSIZE)$(STM32_RAMMOD), 6_A B))
RAM_LEN = 16K
else ifneq (, $(filter $(STM32_ROMSIZE)$(STM32_RAMMOD), 8_A B_A C C_A))
RAM_LEN = 32K
else ifeq ($(STM32_ROMSIZE), D)
RAM_LEN = 48K
else ifeq ($(STM32_ROMSIZE), E)
RAM_LEN = 80K
endif
else ifeq ($(STM32_PINCOUNT), R)
ifeq ($(STM32_ROMSIZE)$(STM32_RAMMOD), 6)
RAM_LEN = 10K
else ifneq (, $(filter $(STM32_ROMSIZE)$(STM32_RAMMOD), 8_A B_A C C_A))
RAM_LEN = 32K
else ifneq (, $(filter $(STM32_ROMSIZE)$(STM32_RAMMOD), B 6_A))
RAM_LEN = 16K
else ifneq (, $(filter $(STM32_ROMSIZE)$(STM32_RAMMOD), D))
RAM_LEN = 48K
else ifneq (, $(filter $(STM32_ROMSIZE)$(STM32_RAMMOD), D_X E))
RAM_LEN = 80K
endif
endif
endif
else ifeq ($(STM32_FAMILY), 4)
ifeq ($(STM32_MODEL2), 1)
RAM_LEN = 40K
else ifeq ($(STM32_MODEL2), 3)
RAM_LEN = 64K
else ifeq ($(STM32_MODEL2), 7)
RAM_LEN = 96K
RAM2_LEN = 32K
else ifeq ($(STM32_MODEL2), 5)
RAM_LEN = 160K
else ifeq ($(STM32_MODEL2), 9)
RAM_LEN = 320K
else ifeq ($(STM32_MODEL2), R)
RAM_LEN = 640K
endif
endif
else ifeq ($(STM32_TYPE), W)
ifeq ($(STM32_FAMILY), B)
ifeq ($(STM32_MODEL), B55)
ifeq ($(STM32_ROMSIZE), C)
RAM_LEN = 128K
else ifneq (, $(filter $(STM32_ROMSIZE), E G))
RAM_LEN = 256K
endif
endif
endif
endif
ifeq ($(RAM_LEN), )
$(warning Unsupported cpu model $(CPU_MODEL) automatically)
endif
ifeq ($(STM32_ROMSIZE), 4)
ROM_LEN = 16K
else ifeq ($(STM32_ROMSIZE), 6)
ROM_LEN = 32K
else ifeq ($(STM32_ROMSIZE), 8)
ROM_LEN = 64K
else ifeq ($(STM32_ROMSIZE), B)
ROM_LEN = 128K
else ifeq ($(STM32_ROMSIZE), Z)
ROM_LEN = 192K
else ifeq ($(STM32_ROMSIZE), C)
ROM_LEN = 256K
else ifeq ($(STM32_ROMSIZE), D)
ROM_LEN = 384K
else ifeq ($(STM32_ROMSIZE), E)
ROM_LEN = 512K
else ifeq ($(STM32_ROMSIZE), F)
ROM_LEN = 768K
else ifeq ($(STM32_ROMSIZE), G)
ROM_LEN = 1024K
else ifeq ($(STM32_ROMSIZE), H)
ROM_LEN = 1536K
else ifeq ($(STM32_ROMSIZE), I)
ROM_LEN = 2048K
endif
ifeq ($(STM32_PINCOUNT), A)
STM32_PINCOUNT = 169
else ifeq ($(STM32_PINCOUNT), B)
STM32_PINCOUNT = 208
else ifeq ($(STM32_PINCOUNT), C)
STM32_PINCOUNT = 48
else ifeq ($(STM32_PINCOUNT), F)
STM32_PINCOUNT = 20
else ifeq ($(STM32_PINCOUNT), G)
STM32_PINCOUNT = 28
else ifeq ($(STM32_PINCOUNT), H)
STM32_PINCOUNT = 40
else ifeq ($(STM32_PINCOUNT), I)
STM32_PINCOUNT = 176
else ifeq ($(STM32_PINCOUNT), J)
STM32_PINCOUNT = 72
else ifeq ($(STM32_PINCOUNT), K)
STM32_PINCOUNT = 32
else ifeq ($(STM32_PINCOUNT), M)
STM32_PINCOUNT = 81
else ifeq ($(STM32_PINCOUNT), N)
STM32_PINCOUNT = 216
else ifeq ($(STM32_PINCOUNT), Q)
STM32_PINCOUNT = 132
else ifeq ($(STM32_PINCOUNT), R)
ifeq ($(STM32_TYPE), W)
STM32_PINCOUNT = 68
else
STM32_PINCOUNT = 64
endif
else ifeq ($(STM32_PINCOUNT), T)
STM32_PINCOUNT = 36
else ifeq ($(STM32_PINCOUNT), U)
STM32_PINCOUNT = 63
else ifeq ($(STM32_PINCOUNT), V)
STM32_PINCOUNT = 100
else ifeq ($(STM32_PINCOUNT), Z)
STM32_PINCOUNT = 144
endif

View File

@ -1,259 +0,0 @@
/*
* Copyright (C) 2017 Freie Universität Berlin
* 2017 OTA keys S.A.
*
* 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 cpu_stm32_common
* @{
*
* @file
* @brief Implementation of STM32 clock configuration
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Vincent Dupont <vincent@otakeys.com>
* @}
*/
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F3) || \
defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32F7)
#include "cpu.h"
#include "stmclk.h"
#include "periph_conf.h"
/* make sure we have all needed information about the clock configuration */
#ifndef CLOCK_HSE
#error "Please provide CLOCK_HSE in your board's perhip_conf.h"
#endif
#ifndef CLOCK_LSE
#error "Please provide CLOCK_LSE in your board's periph_conf.h"
#endif
#ifndef CLOCK_CORECLOCK
#error "Please provide CLOCK_CORECLOCK in your board's periph_conf.h"
#endif
/**
* @name PLL configuration
* @{
*/
#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \
defined(CPU_FAM_STM32F7)
/* figure out which input to use */
#if (CLOCK_HSE)
#define PLL_SRC RCC_PLLCFGR_PLLSRC_HSE
#else
#define PLL_SRC RCC_PLLCFGR_PLLSRC_HSI
#endif
#if defined(CPU_FAM_STM32F2)
#define RCC_PLLCFGR_PLLP_Pos (16U)
#define RCC_PLLCFGR_PLLM_Pos (0U)
#define RCC_PLLCFGR_PLLN_Pos (6U)
#define RCC_PLLCFGR_PLLQ_Pos (24U)
#define RCC_PLLI2SCFGR_PLLI2SN_Pos (6U)
#define RCC_PLLI2SCFGR_PLLI2SR_Pos (28U)
#endif
#if (CLOCK_ENABLE_PLL_I2S)
#ifdef RCC_PLLI2SCFGR_PLLI2SM_Pos
#define PLLI2S_M (CLOCK_PLL_I2S_M << RCC_PLLI2SCFGR_PLLI2SM_Pos)
#else
#define PLLI2S_M (0)
#endif
#define PLLI2S_N (CLOCK_PLL_I2S_N << RCC_PLLI2SCFGR_PLLI2SN_Pos)
#ifdef RCC_PLLI2SCFGR_PLLI2SP_Pos
#define PLLI2S_P (((CLOCK_PLL_I2S_P / 2) - 1) << RCC_PLLI2SCFGR_PLLI2SP_Pos)
#else
#define PLLI2S_P (0)
#endif
#ifdef RCC_PLLI2SCFGR_PLLI2SQ_Pos
#define PLLI2S_Q (CLOCK_PLL_I2S_Q << RCC_PLLI2SCFGR_PLLI2SQ_Pos)
#else
#define PLLI2S_Q (0)
#endif
#if defined(RCC_PLLI2SCFGR_PLLI2SR_Pos) && defined(CLOCK_PLL_I2S_R)
#define PLLI2S_R (CLOCK_PLL_I2S_R << RCC_PLLI2SCFGR_PLLI2SR_Pos)
#else
#define PLLI2S_R (0)
#endif
#endif /* CLOCK_ENABLE_PLLI_2S */
#if (CLOCK_ENABLE_PLL_SAI)
#ifdef RCC_PLLSAICFGR_PLLSAIN_Pos
#define PLLSAI_M (CLOCK_PLL_SAI_M << RCC_PLLSAICFGR_PLLSAIM_Pos)
#else
#define PLLSAI_M (0)
#endif
#define PLLSAI_N (CLOCK_PLL_SAI_N << RCC_PLLSAICFGR_PLLSAIN_Pos)
#ifdef RCC_PLLSAICFGR_PLLSAIP_Pos
#define PLLSAI_P (((CLOCK_PLL_SAI_P / 2) - 1) << RCC_PLLSAICFGR_PLLSAIP_Pos)
#else
#define PLLSAI_P (0)
#endif
#define PLLSAI_Q (CLOCK_PLL_SAI_Q << RCC_PLLSAICFGR_PLLSAIQ_Pos)
#if defined(RCC_PLLSAICFGR_PLLSAIR_Pos) && defined(CLOCK_PLL_SAI_R)
#define PLLSAI_R (CLOCK_PLL_SAI_R << RCC_PLLSAICFGR_PLLSAIR_Pos)
#else
#define PLLSAI_R (0)
#endif
#endif /* CLOCK_ENABLE_PLL_SAI */
/* now we get the actual bitfields */
#define PLL_P (((CLOCK_PLL_P / 2) - 1) << RCC_PLLCFGR_PLLP_Pos)
#define PLL_M (CLOCK_PLL_M << RCC_PLLCFGR_PLLM_Pos)
#define PLL_N (CLOCK_PLL_N << RCC_PLLCFGR_PLLN_Pos)
#define PLL_Q (CLOCK_PLL_Q << RCC_PLLCFGR_PLLQ_Pos)
#if defined(RCC_PLLCFGR_PLLR_Pos) && defined(CLOCK_PLL_R)
#define PLL_R (CLOCK_PLL_R << RCC_PLLCFGR_PLLR_Pos)
#else
#define PLL_R (0)
#endif
#elif defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F3)
#if (CLOCK_HSE)
#define PLL_SRC (RCC_CFGR_PLLSRC_HSE_PREDIV | RCC_CFGR_PLLXTPRE_HSE_PREDIV_DIV1)
#else
#define PLL_SRC (RCC_CFGR_PLLSRC_HSI_DIV2)
#endif
#define PLL_MUL ((CLOCK_PLL_MUL - 2) << 18)
#define PLL_PREDIV (CLOCK_PLL_PREDIV - 1)
#if defined(CPU_FAM_STM32F0)
#define CLOCK_APB2_DIV (0)
#endif
#elif defined(CPU_FAM_STM32F1)
#if CLOCK_HSE
#define PLL_SRC (RCC_CFGR_PLLSRC) /* HSE */
#else
#define PLL_SRC (0) /* HSI / 2 */
#endif
#define PLL_MUL ((CLOCK_PLL_MUL - 2) << 18)
#define PLL_PREDIV (CLOCK_PLL_PREDIV - 1)
#define RCC_CR_HSITRIM_4 (1 << 7)
#define RCC_CFGR_PLLMUL RCC_CFGR_PLLMULL
#endif
/** @} */
/**
* @name Deduct the needed flash wait states from the core clock frequency
* @{
*/
#if defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F3)
#define FLASH_WAITSTATES ((CLOCK_CORECLOCK - 1) / 24000000U)
#else
#define FLASH_WAITSTATES (CLOCK_CORECLOCK / 30000000U)
#endif
/* we enable I+D cashes, pre-fetch, and we set the actual number of
* needed flash wait states */
#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4)
#define FLASH_ACR_CONFIG (FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_PRFTEN | FLASH_WAITSTATES)
#elif defined(CPU_FAM_STM32F7)
#define FLASH_ACR_CONFIG (FLASH_ACR_ARTEN | FLASH_ACR_PRFTEN | FLASH_WAITSTATES)
#elif defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F3)
#define FLASH_ACR_CONFIG (FLASH_ACR_PRFTBE | FLASH_WAITSTATES)
#endif
/** @} */
void stmclk_init_sysclk(void)
{
/* disable any interrupts. Global interrupts could be enabled if this is
* called from some kind of bootloader... */
unsigned is = irq_disable();
RCC->CIR = 0;
/* enable HSI clock for the duration of initialization */
stmclk_enable_hsi();
/* use HSI as system clock while we do any further configuration and
* configure the AHB and APB clock dividers as configure by the board */
RCC->CFGR = (RCC_CFGR_SW_HSI | CLOCK_AHB_DIV |
CLOCK_APB1_DIV | CLOCK_APB2_DIV);
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) {}
/* Flash config */
FLASH->ACR = FLASH_ACR_CONFIG;
/* disable all active clocks except HSI -> resets the clk configuration */
RCC->CR = (RCC_CR_HSION | RCC_CR_HSITRIM_4);
#if (CLOCK_MCO1_SRC)
#ifndef RCC_CFGR_MCO1
#error "stmclk: no MCO1 on this device"
#endif
RCC->CFGR |= CLOCK_MCO1_SRC | CLOCK_MCO1_PRE;
#endif
#if (CLOCK_MCO2_SRC)
#ifndef RCC_CFGR_MCO2
#error "stmclk: no MCO2 on this device"
#endif
RCC->CFGR |= CLOCK_MCO2_SRC | CLOCK_MCO2_PRE;
#endif
/* if configured, we need to enable the HSE clock now */
#if (CLOCK_HSE)
RCC->CR |= (RCC_CR_HSEON);
while (!(RCC->CR & RCC_CR_HSERDY)) {}
#endif
#if CLOCK_USE_ALT_48MHZ
RCC->DCKCFGR2 |= RCC_DCKCFGR2_CK48MSEL;
#endif
/* now we can safely configure and start the PLL */
#if defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || \
defined(CPU_FAM_STM32F7)
RCC->PLLCFGR = (PLL_SRC | PLL_M | PLL_N | PLL_P | PLL_Q | PLL_R);
#elif defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) || \
defined(CPU_FAM_STM32F3)
/* reset PLL configuration bits */
RCC->CFGR &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMUL);
/* set PLL configuration */
RCC->CFGR |= PLL_SRC | PLL_MUL;
#if CLOCK_PLL_PREDIV == 2
RCC->CFGR |= RCC_CFGR_PLLXTPRE; /* PREDIV == 2 */
#elif CLOCK_PLL_PREDIV > 2
RCC->CFGR2 = PLL_PREDIV; /* PREDIV > 2 */
#elif CLOCK_PLL_PREDIV == 0
#error "CLOCK_PLL_PREDIV invalid"
#endif
#endif
RCC->CR |= (RCC_CR_PLLON);
while (!(RCC->CR & RCC_CR_PLLRDY)) {}
/* now that the PLL is running, we use it as system clock */
RCC->CFGR |= (RCC_CFGR_SW_PLL);
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) {}
stmclk_disable_hsi();
#if (CLOCK_ENABLE_PLL_I2S)
RCC->PLLI2SCFGR = (CLOCK_PLL_I2S_SRC | PLLI2S_M | PLLI2S_N | PLLI2S_P | PLLI2S_Q | PLLI2S_R);
RCC->CR |= (RCC_CR_PLLI2SON);
while (!(RCC->CR & RCC_CR_PLLI2SRDY)) {}
#endif /* CLOCK_ENABLE_PLLI2S */
#if (CLOCK_ENABLE_PLL_SAI)
RCC->PLLSAICFGR = (PLLSAI_M | PLLSAI_N | PLLSAI_P | PLLSAI_Q | PLLSAI_R);
RCC->CR |= (RCC_CR_PLLSAION);
while (!(RCC->CR & RCC_CR_PLLSAIRDY)) {}
#endif
irq_restore(is);
}
#else
typedef int dont_be_pedantic;
#endif /* defined(CPU_FAM_STM32F0) || defined(CPU_FAM_STM32F1) ||
* defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F3) ||
* defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32F7) */

View File

@ -1,110 +0,0 @@
/*
* Copyright (C) 2017 Freie Universität Berlin
* 2017 OTA keys S.A.
*
* 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 cpu_stm32_common
* @{
*
* @file
* @brief Implementation of common STM32 clock configuration functions
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Vincent Dupont <vincent@otakeys.com>
* @}
*/
#include "cpu.h"
#include "stmclk.h"
#include "periph_conf.h"
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32F7) || \
defined(CPU_FAM_STM32WB)
#define REG_PWR_CR CR1
#define BIT_CR_DBP PWR_CR1_DBP
#else
#define REG_PWR_CR CR
#define BIT_CR_DBP PWR_CR_DBP
#endif
#if defined (CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
#define REG_LSE CSR
#define BIT_LSEON RCC_CSR_LSEON
#define BIT_LSERDY RCC_CSR_LSERDY
#else
#define REG_LSE BDCR
#define BIT_LSEON RCC_BDCR_LSEON
#define BIT_LSERDY RCC_BDCR_LSERDY
#endif
#if defined (CPU_FAM_STM32WB)
#define RCC_CFGR_SWS_HSI RCC_CFGR_SWS_0
#define RCC_CSR_LSION RCC_CSR_LSI1ON
#define RCC_CSR_LSIRDY RCC_CSR_LSI1RDY
#endif
#ifndef CLOCK_HSE
#define CLOCK_HSE (0U)
#endif
#ifndef CLOCK_LSE
#define CLOCK_LSE (0U)
#endif
void stmclk_enable_hsi(void)
{
RCC->CR |= RCC_CR_HSION;
while (!(RCC->CR & RCC_CR_HSIRDY)) {}
}
void stmclk_disable_hsi(void)
{
/* we only disable the HSI clock if not used as input for the PLL and if
* not used directly as system clock */
if (CLOCK_HSE) {
if ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) {
RCC->CR &= ~(RCC_CR_HSION);
}
}
}
void stmclk_enable_lfclk(void)
{
if (CLOCK_LSE) {
stmclk_dbp_unlock();
RCC->REG_LSE |= BIT_LSEON;
while (!(RCC->REG_LSE & BIT_LSERDY)) {}
stmclk_dbp_lock();
}
else {
RCC->CSR |= RCC_CSR_LSION;
while (!(RCC->CSR & RCC_CSR_LSIRDY)) {}
}
}
void stmclk_disable_lfclk(void)
{
if (CLOCK_LSE) {
stmclk_dbp_unlock();
RCC->REG_LSE &= ~(BIT_LSEON);
while (!(RCC->REG_LSE & BIT_LSERDY)) {}
stmclk_dbp_lock();
}
else {
RCC->CSR &= ~(RCC_CSR_LSION);
}
}
void stmclk_dbp_unlock(void)
{
PWR->REG_PWR_CR |= BIT_CR_DBP;
}
void stmclk_dbp_lock(void)
{
PWR->REG_PWR_CR &= ~(BIT_CR_DBP);
}

View File

@ -1,119 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin
* 2017 Inria
* 2018 Kaspar Schleiser <kaspar@schleiser.de>
*
* 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 cpu_stm32_common
* @{
*
* @file
* @brief Implementation of STM32 clock configuration
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
*
* @}
*/
#include "cpu.h"
#include "board.h"
#include "periph_conf.h"
#include "periph/init.h"
#if defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1)
/* Check the source to be used for the PLL */
#if defined(CLOCK_HSI) && defined(CLOCK_HSE)
#error "Only provide one of two CLOCK_HSI/CLOCK_HSE"
#elif CLOCK_HSI
#define CLOCK_CR_SOURCE RCC_CR_HSION
#define CLOCK_CR_SOURCE_RDY RCC_CR_HSIRDY
#define CLOCK_PLL_SOURCE RCC_CFGR_PLLSRC_HSI
#elif CLOCK_HSE
#define CLOCK_CR_SOURCE RCC_CR_HSEON
#define CLOCK_CR_SOURCE_RDY RCC_CR_HSERDY
#define CLOCK_PLL_SOURCE RCC_CFGR_PLLSRC_HSE
#else
#error "Please provide CLOCK_HSI or CLOCK_HSE in boards/NAME/includes/perhip_cpu.h"
#endif
/**
* @brief Configure the controllers clock system
*
* The clock initialization make the following assumptions:
* - the external HSE clock from an external oscillator is used as base clock
* - the internal PLL circuit is used for clock refinement
*
* Use the following formulas to calculate the needed values:
*
* SYSCLK = ((HSE_VALUE / CLOCK_PLL_M) * CLOCK_PLL_N) / CLOCK_PLL_P
* USB, SDIO and RNG Clock = ((HSE_VALUE / CLOCK_PLL_M) * CLOCK_PLL_N) / CLOCK_PLL_Q
*
* The actual used values are specified in the board's `periph_conf.h` file.
*
* NOTE: currently there is not timeout for initialization of PLL and other locks
* -> when wrong values are chosen, the initialization could stall
*/
void stmclk_init_sysclk(void)
{
/* Reset the RCC clock configuration to the default reset state(for debug purpose) */
/* Set MSION bit */
RCC->CR |= RCC_CR_MSION;
/* Reset SW, HPRE, PPRE1, PPRE2, MCOSEL and MCOPRE bits */
RCC->CFGR &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLDIV | RCC_CFGR_PLLMUL);
/* Reset HSION, HSEON, CSSON and PLLON bits */
RCC->CR &= ~(RCC_CR_HSION | RCC_CR_HSEON | RCC_CR_HSEBYP | RCC_CR_CSSON | RCC_CR_PLLON);
/* Disable all interrupts */
#if defined(CPU_FAM_STM32L0)
RCC->CICR = 0x0;
#elif defined(CPU_FAM_STM32L1)
RCC->CIR = 0x0;
#else
#error unexpected MCU
#endif
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration */
/* Enable high speed clock source */
RCC->CR |= CLOCK_CR_SOURCE;
/* Wait till the high speed clock source is ready
* NOTE: the MCU will stay here forever if you use an external clock source and it's not connected */
while (!(RCC->CR & CLOCK_CR_SOURCE_RDY)) {}
#if defined(CPU_FAM_STM32L1)
FLASH->ACR |= FLASH_ACR_ACC64;
#endif
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTEN;
/* Flash 1 wait state */
FLASH->ACR |= CLOCK_FLASH_LATENCY;
/* Select the Voltage Range 1 (1.8 V) */
PWR->CR = PWR_CR_VOS_0;
/* Wait Until the Voltage Regulator is ready */
while((PWR->CSR & PWR_CSR_VOSF) != 0) {}
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)CLOCK_AHB_DIV;
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)CLOCK_APB2_DIV;
/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)CLOCK_APB1_DIV;
/* PLL configuration: PLLCLK = CLOCK_SOURCE / PLL_DIV * PLL_MUL */
RCC->CFGR &= ~((uint32_t)(RCC_CFGR_PLLSRC | RCC_CFGR_PLLDIV | RCC_CFGR_PLLMUL));
RCC->CFGR |= (uint32_t)(CLOCK_PLL_SOURCE | CLOCK_PLL_DIV | CLOCK_PLL_MUL);
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while ((RCC->CR & RCC_CR_PLLRDY) == 0) {}
/* Select PLL as system clock source */
RCC->CFGR &= ~((uint32_t)(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) {}
}
#endif /* defined(CPU_FAM_STM32L0) || defined(CPU_FAM_STM32L1) */

View File

@ -1,203 +0,0 @@
/*
* Copyright (C) 2017 Freie Universität Berlin
* 2017 OTA keys S.A.
* 2017 HAW-Hamburg
*
* 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 cpu_stm32_common
* @{
*
* @file
* @brief Implementation of STM32 clock configuration
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Nick van IJzendoorn <nijzendoorn@engineering-spirit.nl>
* @author Vincent Dupont <vincent@otakeys.com>
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
* @author Francisco Molina <francois-xavier.molina@inria.fr>
* @}
*/
#include "cpu.h"
#include "stmclk.h"
#include "periph_conf.h"
#if defined(CPU_FAM_STM32L4) || defined(CPU_FAM_STM32WB)
/* make sure we have all needed information about the clock configuration */
#ifndef CLOCK_HSE
#error "Please provide CLOCK_HSE in your board's perhip_conf.h"
#endif
#ifndef CLOCK_LSE
#error "Please provide CLOCK_LSE in your board's periph_conf.h"
#endif
#if !defined(CLOCK_PLL_M) || !defined(CLOCK_PLL_N) || !defined(CLOCK_PLL_R)
#error "Please provide the PLL configuration in your board's periph_conf.h"
#endif
/* map CMSIS defines not present in stm32wb55xx.h */
#if defined(CPU_FAM_STM32WB)
#define RCC_PLLCFGR_PLLSRC_HSE (RCC_PLLCFGR_PLLSRC_0 | RCC_PLLCFGR_PLLSRC_1)
#define RCC_PLLCFGR_PLLSRC_MSI (RCC_PLLCFGR_PLLSRC_0)
#define RCC_CFGR_SW_MSI (0x00000000U)
#define RCC_CFGR_SW_HSI (RCC_CFGR_SW_0)
#define RCC_CFGR_SW_HSE (RCC_CFGR_SW_1)
#define RCC_CFGR_SW_PLL (RCC_CFGR_SW_1 + RCC_CFGR_SW_0)
#define RCC_CFGR_SWS_MSI (0x00000000U)
#define RCC_CFGR_SWS_HSI (RCC_CFGR_SWS_0)
#define RCC_CFGR_SWS_HSE (RCC_CFGR_SWS_1)
#define RCC_CFGR_SWS_PLL (RCC_CFGR_SWS_1 + RCC_CFGR_SWS_0)
#endif
/**
* @name PLL configuration
* @{
*/
/* figure out which input to use */
#if (CLOCK_HSE)
#define PLL_IN CLOCK_HSE
#define PLL_SRC RCC_PLLCFGR_PLLSRC_HSE
#else
#define PLL_IN (48000000) /* MSI @ 48MHz */
#define PLL_SRC RCC_PLLCFGR_PLLSRC_MSI
#endif
/**check configuration and get the corresponding bitfields */
#if (CLOCK_PLL_M < 1 || CLOCK_PLL_M > 8)
#error "PLL configuration: PLL M value is out of range"
#endif
#define PLL_M ((CLOCK_PLL_M - 1) << RCC_PLLCFGR_PLLM_Pos)
#if (CLOCK_PLL_N < 8 || CLOCK_PLL_N > 86)
#error "PLL configuration: PLL N value is out of range"
#endif
#define PLL_N (CLOCK_PLL_N << RCC_PLLCFGR_PLLN_Pos)
#if defined(CPU_FAM_STM32WB)
#if (CLOCK_PLL_R < 1 || CLOCK_PLL_R > 8)
#error "PLL configuration: PLL R value is invalid"
#else
#define PLL_R ((CLOCK_PLL_R - 1)<< RCC_PLLCFGR_PLLR_Pos)
#endif
#else
#if (CLOCK_PLL_R == 2)
#define PLL_R (0)
#elif (CLOCK_PLL_R == 4)
#define PLL_R (RCC_PLLCFGR_PLLR_0)
#elif (CLOCK_PLL_R == 6)
#define PLL_R (RCC_PLLCFGR_PLLR_1)
#elif (CLOCK_PLL_R == 8)
#define PLL_R (RCC_PLLCFGR_PLLR_0 | RCC_PLLCFGR_PLLR_1)
#else
#error "PLL configuration: PLL R value is invalid"
#endif
#endif
/** @} */
/**
* @name Deduct the needed flash wait states from the core clock frequency
* @{
*/
#if defined(CPU_FAM_STM32WB)
#if (CLOCK_AHB <= 64000000)
#define FLASH_WAITSTATES ((CLOCK_AHB - 1) / 18000000U)
#else
#define FLASH_WAITSTATES FLASH_ACR_LATENCY_3WS
#endif
#else
#define FLASH_WAITSTATES ((CLOCK_AHB - 1) / 16000000U)
#endif
/** @} */
void stmclk_init_sysclk(void)
{
/* disable any interrupts. Global interrupts could be enabled if this is
* called from some kind of bootloader... */
unsigned is = irq_disable();
RCC->CIER = 0;
/* enable HSI clock for the duration of initialization */
stmclk_enable_hsi();
/* use HSI as system clock while we do any further configuration and
* configure the AHB and APB clock dividers as configure by the board */
RCC->CFGR = (RCC_CFGR_SW_HSI | CLOCK_AHB_DIV |
CLOCK_APB1_DIV | CLOCK_APB2_DIV);
#if defined(CPU_FAM_STM32WB)
/* Use HSE/2 for radios systems */
RCC->EXTCFGR = (RCC_EXTCFGR_RFCSS | CLOCK_EXTAHB_DIV);
#endif
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) {}
/* we enable I+D cashes, pre-fetch, and we set the actual number of
* needed flash wait states */
FLASH->ACR = (FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_PRFTEN |
FLASH_WAITSTATES);
/* disable all active clocks except HSI -> resets the clk configuration
* Note: on STM32L4x5 & STM32L4x6 this disables the following:
PLLSAI1, PLLSAI2, Main PLL (via PLLON),
Clock security system (via CSSON), MSI clock PLL (via MSIPLLEN),
HSE crystal oscillator bypass (via HSEBYP), HSE,
HSI16 automatic start from Stop (via HSIASFS),
HSI16 always enable for peripheral kernels (via HSIKERON).
Additionally it configures the MSI clock range (MSIRANGE) to
~100 kHz and the MSI clock to be based on MSISRANGE in RCC_CSR
(instead of MSIRANGE in the RCC_CR) */
RCC->CR = (RCC_CR_HSION);
#if (CLOCK_HSE)
/* if configured, we need to enable the HSE clock now */
RCC->CR |= (RCC_CR_HSEON);
while (!(RCC->CR & RCC_CR_HSERDY)) {}
#endif
#if ((CLOCK_HSE == 0) || CLOCK_MSI_ENABLE)
/* reset clock to MSI with 48MHz, disables all other clocks */
#if defined(CPU_FAM_STM32WB)
RCC->CR |= (RCC_CR_MSIRANGE_11 | RCC_CR_MSION);
#else
RCC->CR |= (RCC_CR_MSIRANGE_11 | RCC_CR_MSION | RCC_CR_MSIRGSEL);
#endif
while (!(RCC->CR & RCC_CR_MSIRDY)) {}
/* select the MSI clock for the 48MHz clock tree (USB, RNG) */
RCC->CCIPR = (RCC_CCIPR_CLK48SEL_0 | RCC_CCIPR_CLK48SEL_1);
#if (CLOCK_MSI_LSE_PLL && CLOCK_LSE)
/* configure the low speed clock domain */
stmclk_enable_lfclk();
/* now we can enable the MSI PLL mode to enhance accuracy of the MSI*/
RCC->CR |= RCC_CR_MSIPLLEN;
while (!(RCC->CR & RCC_CR_MSIRDY)) {}
#endif /* (CLOCK_MSI_LSE_PLL && CLOCK_LSE) */
#endif /* ((CLOCK_HSE == 0) || CLOCK_MSI_ENABLE) */
/* now we can safely configure and start the PLL */
RCC->PLLCFGR = (PLL_SRC | PLL_M | PLL_N | PLL_R | RCC_PLLCFGR_PLLREN);
RCC->CR |= (RCC_CR_PLLON);
while (!(RCC->CR & RCC_CR_PLLRDY)) {}
/* now that the PLL is running, we use it as system clock */
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) {}
stmclk_disable_hsi();
irq_restore(is);
#ifdef MODULE_PERIPH_RTT
/* Ensure LPTIM1 clock source (LSI or LSE) is correctly reset when initializing
the clock, this is particularly useful after waking up from deep sleep */
#if CLOCK_LSE
RCC->CCIPR |= RCC_CCIPR_LPTIM1SEL_0 | RCC_CCIPR_LPTIM1SEL_1;
#else
RCC->CCIPR |= RCC_CCIPR_LPTIM1SEL_0;
#endif /* CLOCK_LSE */
#endif /* MODULE_PERIPH_RTT */
}
#endif

View File

@ -1,10 +0,0 @@
# define the module that is build
MODULE = cpu
# add a list of subdirectories, that should also be build
DIRS = periph $(RIOTCPU)/cortexm_common $(RIOTCPU)/stm32_common
# (file triggers compiler bug. see #5775)
SRC_NOLTO += vectors.c
include $(RIOTBASE)/Makefile.base

View File

@ -1 +0,0 @@
include $(RIOTCPU)/stm32_common/Makefile.dep

View File

@ -1,9 +0,0 @@
CPU_ARCH = cortex-m0
CPU_FAM = stm32f0
ifeq (,$(filter nucleo-f031k6,$(BOARD)))
FEATURES_PROVIDED += periph_flashpage
FEATURES_PROVIDED += periph_flashpage_raw
endif
-include $(RIOTCPU)/stm32_common/Makefile.features

View File

@ -1,2 +0,0 @@
include $(RIOTCPU)/stm32_common/Makefile.include
include $(RIOTMAKE)/arch/cortexm.inc.mk

View File

@ -1,83 +0,0 @@
/*
* Copyright (C) 2016 Freie Universität Berlin
* 2016 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.
*/
/**
* @defgroup cpu_stm32f0 STM32F0
* @brief STM32F0 specific code
* @ingroup cpu
* @{
*
* @file
* @brief Implementation specific CPU configuration options
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
*/
#ifndef CPU_CONF_H
#define CPU_CONF_H
#include "cpu_conf_common.h"
#include "vendor/stm32f0xx.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief ARM Cortex-M specific CPU configuration
* @{
*/
#define CPU_DEFAULT_IRQ_PRIO (1U)
#if defined(CPU_LINE_STM32F030x8)
#define CPU_IRQ_NUMOF (29U)
#elif defined(CPU_LINE_STM32F031x6) || defined(CPU_LINE_STM32F030x4)
#define CPU_IRQ_NUMOF (28U)
#elif defined(CPU_LINE_STM32F051x8) || defined(CPU_LINE_STM32F091xC)
#define CPU_IRQ_NUMOF (31U)
#else
#define CPU_IRQ_NUMOF (32U)
#endif
#define CPU_FLASH_BASE FLASH_BASE
/** @} */
/**
* @brief Flash page configuration
*
* STM32F03x, STM32F04x, STM32F05x: up to 64 pages of 1K
* STM32F07x, STM32F09x: up to 128 pages of 2K
*
* @{
*/
#if defined(CPU_LINE_STM32F091xC) || defined(CPU_LINE_STM32F072xB) \
|| defined(CPU_LINE_STM32F030xC)
#define FLASHPAGE_SIZE (2048U)
#elif defined(CPU_LINE_STM32F051x8) || defined(CPU_LINE_STM32F042x6) \
|| defined(CPU_LINE_STM32F070xB) || defined(CPU_LINE_STM32F030x8) \
|| defined(CPU_LINE_STM32F030x4)
#define FLASHPAGE_SIZE (1024U)
#endif
#define FLASHPAGE_NUMOF (STM32_FLASHSIZE / FLASHPAGE_SIZE)
/* The minimum block size which can be written is 2B. However, the erase
* block is always FLASHPAGE_SIZE.
*/
#define FLASHPAGE_RAW_BLOCKSIZE (2U)
/* Writing should be always 4 bytes aligned */
#define FLASHPAGE_RAW_ALIGNMENT (4U)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* CPU_CONF_H */
/** @} */

View File

@ -1,75 +0,0 @@
/*
* Copyright (C) 2015-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.
*/
/**
* @ingroup cpu_stm32f0
* @{
*
* @file
* @brief CPU specific definitions for internal peripheral handling
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef PERIPH_CPU_H
#define PERIPH_CPU_H
#include "periph_cpu_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Starting address of the CPU ID
*/
#define CPUID_ADDR (0x1ffff7ac)
/**
* @brief Available ports on the STM32F0 family
*/
enum {
PORT_A = 0, /**< port A */
PORT_B = 1, /**< port B */
PORT_C = 2, /**< port C */
PORT_D = 3, /**< port D */
PORT_E = 4, /**< port E */
PORT_F = 5, /**< port F */
};
#ifndef DOXYGEN
/**
* @brief Override ADC resolution values
* @{
*/
#define HAVE_ADC_RES_T
typedef enum {
ADC_RES_6BIT = (0x3 << 3), /**< ADC resolution: 6 bit */
ADC_RES_8BIT = (0x2 << 3), /**< ADC resolution: 8 bit */
ADC_RES_10BIT = (0x1 << 3), /**< ADC resolution: 10 bit */
ADC_RES_12BIT = (0x0 << 3), /**< ADC resolution: 12 bit */
ADC_RES_14BIT = (0xfe), /**< not applicable */
ADC_RES_16BIT = (0xff) /**< not applicable */
} adc_res_t;
/** @} */
#endif /* ndef DOXYGEN */
/**
* @brief ADC line configuration values
*/
typedef struct {
gpio_t pin; /**< pin to use */
uint8_t chan; /**< internal channel the pin is connected to */
} adc_conf_t;
#ifdef __cplusplus
}
#endif
#endif /* PERIPH_CPU_H */
/** @} */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,218 +0,0 @@
/**
******************************************************************************
* @file stm32f0xx.h
* @author MCD Application Team
* @brief CMSIS STM32F0xx Device Peripheral Access Layer Header File.
*
* The file is the unique include file that the application programmer
* is using in the C source code, usually in main.c. This file contains:
* - Configuration section that allows to select:
* - The STM32F0xx device used in the target application
* - To use or not the peripheral’s drivers in application code(i.e.
* code will be based on direct access to peripheral’s registers
* rather than drivers API), this option is controlled by
* "#define USE_HAL_DRIVER"
*
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32f0xx
* @{
*/
#ifndef __STM32F0xx_H
#define __STM32F0xx_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/** @addtogroup Library_configuration_section
* @{
*/
/**
* @brief STM32 Family
*/
#if !defined (STM32F0)
#define STM32F0
#endif /* STM32F0 */
/* Uncomment the line below according to the target STM32 device used in your
application
*/
#if !defined (STM32F030x6) && !defined (STM32F030x8) && \
!defined (STM32F031x6) && !defined (STM32F038xx) && \
!defined (STM32F042x6) && !defined (STM32F048xx) && !defined (STM32F070x6) && \
!defined (STM32F051x8) && !defined (STM32F058xx) && \
!defined (STM32F071xB) && !defined (STM32F072xB) && !defined (STM32F078xx) && !defined (STM32F070xB) && \
!defined (STM32F091xC) && !defined (STM32F098xx) && !defined (STM32F030xC)
/* #define STM32F030x6 */ /*!< STM32F030x4, STM32F030x6 Devices (STM32F030xx microcontrollers where the Flash memory ranges between 16 and 32 Kbytes) */
/* #define STM32F030x8 */ /*!< STM32F030x8 Devices (STM32F030xx microcontrollers where the Flash memory is 64 Kbytes) */
/* #define STM32F031x6 */ /*!< STM32F031x4, STM32F031x6 Devices (STM32F031xx microcontrollers where the Flash memory ranges between 16 and 32 Kbytes) */
/* #define STM32F038xx */ /*!< STM32F038xx Devices (STM32F038xx microcontrollers where the Flash memory is 32 Kbytes) */
/* #define STM32F042x6 */ /*!< STM32F042x4, STM32F042x6 Devices (STM32F042xx microcontrollers where the Flash memory ranges between 16 and 32 Kbytes) */
/* #define STM32F048x6 */ /*!< STM32F048xx Devices (STM32F042xx microcontrollers where the Flash memory is 32 Kbytes) */
/* #define STM32F051x8 */ /*!< STM32F051x4, STM32F051x6, STM32F051x8 Devices (STM32F051xx microcontrollers where the Flash memory ranges between 16 and 64 Kbytes) */
/* #define STM32F058xx */ /*!< STM32F058xx Devices (STM32F058xx microcontrollers where the Flash memory is 64 Kbytes) */
/* #define STM32F070x6 */ /*!< STM32F070x6 Devices (STM32F070x6 microcontrollers where the Flash memory ranges between 16 and 32 Kbytes) */
/* #define STM32F070xB */ /*!< STM32F070xB Devices (STM32F070xB microcontrollers where the Flash memory ranges between 64 and 128 Kbytes) */
/* #define STM32F071xB */ /*!< STM32F071x8, STM32F071xB Devices (STM32F071xx microcontrollers where the Flash memory ranges between 64 and 128 Kbytes) */
/* #define STM32F072xB */ /*!< STM32F072x8, STM32F072xB Devices (STM32F072xx microcontrollers where the Flash memory ranges between 64 and 128 Kbytes) */
/* #define STM32F078xx */ /*!< STM32F078xx Devices (STM32F078xx microcontrollers where the Flash memory is 128 Kbytes) */
/* #define STM32F030xC */ /*!< STM32F030xC Devices (STM32F030xC microcontrollers where the Flash memory is 256 Kbytes) */
/* #define STM32F091xC */ /*!< STM32F091xB, STM32F091xC Devices (STM32F091xx microcontrollers where the Flash memory ranges between 128 and 256 Kbytes) */
/* #define STM32F098xx */ /*!< STM32F098xx Devices (STM32F098xx microcontrollers where the Flash memory is 256 Kbytes) */
#endif
/* Tip: To avoid modifying this file each time you need to switch between these
devices, you can define the device in your toolchain compiler preprocessor.
*/
#if !defined (USE_HAL_DRIVER)
/**
* @brief Comment the line below if you will not use the peripherals drivers.
In this case, these drivers will not be included and the application code will
be based on direct access to peripherals registers
*/
/*#define USE_HAL_DRIVER */
#endif /* USE_HAL_DRIVER */
/**
* @brief CMSIS Device version number V2.3.2
*/
#define __STM32F0_DEVICE_VERSION_MAIN (0x02) /*!< [31:24] main version */
#define __STM32F0_DEVICE_VERSION_SUB1 (0x03) /*!< [23:16] sub1 version */
#define __STM32F0_DEVICE_VERSION_SUB2 (0x02) /*!< [15:8] sub2 version */
#define __STM32F0_DEVICE_VERSION_RC (0x00) /*!< [7:0] release candidate */
#define __STM32F0_DEVICE_VERSION ((__STM32F0_DEVICE_VERSION_MAIN << 24)\
|(__STM32F0_DEVICE_VERSION_SUB1 << 16)\
|(__STM32F0_DEVICE_VERSION_SUB2 << 8 )\
|(__STM32F0_DEVICE_VERSION_RC))
/**
* @}
*/
/** @addtogroup Device_Included
* @{
*/
#if defined(STM32F030x4)
#include "stm32f030x4.h"
#elif defined(STM32F030x6)
#include "stm32f030x6.h"
#elif defined(STM32F030x8)
#include "stm32f030x8.h"
#elif defined(STM32F031x6)
#include "stm32f031x6.h"
#elif defined(STM32F038xx)
#include "stm32f038xx.h"
#elif defined(STM32F042x6)
#include "stm32f042x6.h"
#elif defined(STM32F048xx)
#include "stm32f048xx.h"
#elif defined(STM32F051x8)
#include "stm32f051x8.h"
#elif defined(STM32F058xx)
#include "stm32f058xx.h"
#elif defined(STM32F070x6)
#include "stm32f070x6.h"
#elif defined(STM32F070xB)
#include "stm32f070xb.h"
#elif defined(STM32F071xB)
#include "stm32f071xb.h"
#elif defined(STM32F072xB)
#include "stm32f072xb.h"
#elif defined(STM32F078xx)
#include "stm32f078xx.h"
#elif defined(STM32F091xC)
#include "stm32f091xc.h"
#elif defined(STM32F098xx)
#include "stm32f098xx.h"
#elif defined(STM32F030xC)
#include "stm32f030xc.h"
#else
#error "Please select first the target STM32F0xx device used in your application (in stm32f0xx.h file)"
#endif
/**
* @}
*/
/** @addtogroup Exported_macros
* @{
*/
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT))
#define READ_BIT(REG, BIT) ((REG) & (BIT))
#define CLEAR_REG(REG) ((REG) = (0x0))
#define WRITE_REG(REG, VAL) ((REG) = (VAL))
#define READ_REG(REG) ((REG))
#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))
/**
* @}
*/
#if defined (USE_HAL_DRIVER)
#include "stm32f0xx_hal.h"
#endif /* USE_HAL_DRIVER */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __STM32F0xx_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -1 +0,0 @@
include $(RIOTMAKE)/periph.mk

View File

@ -1,103 +0,0 @@
/*
* Copyright (C) 2014-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.
*/
/**
* @ingroup cpu_stm32f0
* @ingroup drivers_periph_adc
* @{
*
* @file
* @brief Low-level ADC driver implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include "cpu.h"
#include "mutex.h"
#include "periph/adc.h"
/**
* @brief Maximum allowed ADC clock speed
*/
#define MAX_ADC_SPEED (12000000U)
/**
* @brief Load the ADC configuration
*/
static const adc_conf_t adc_config[] = ADC_CONFIG;
/**
* @brief Allocate locks for all three available ADC device
*
* All STM32F0 CPUs we support so far only come with a single ADC device.
*/
static mutex_t lock = MUTEX_INIT;
static inline void prep(void)
{
mutex_lock(&lock);
periph_clk_en(APB2, RCC_APB2ENR_ADCEN);
}
static inline void done(void)
{
periph_clk_dis(APB2, RCC_APB2ENR_ADCEN);
mutex_unlock(&lock);
}
int adc_init(adc_t line)
{
/* make sure the given line is valid */
if (line >= ADC_NUMOF) {
return -1;
}
/* lock and power on the device */
prep();
/*configure the pin */
gpio_init_analog(adc_config[line].pin);
/* reset configuration */
ADC1->CFGR2 = 0;
/* enable device */
ADC1->CR = ADC_CR_ADEN;
/* configure sampling time to save value */
ADC1->SMPR = 0x3; /* 28.5 ADC clock cycles */
/* power off an release device for now */
done();
return 0;
}
int32_t adc_sample(adc_t line, adc_res_t res)
{
int sample;
/* check if resolution is applicable */
if (res > 0xf0) {
return -1;
}
/* lock and power on the ADC device */
prep();
/* set resolution and channel */
ADC1->CFGR1 = res;
ADC1->CHSELR = (1 << adc_config[line].chan);
/* start conversion and wait for results */
ADC1->CR |= ADC_CR_ADSTART;
while (!(ADC1->ISR & ADC_ISR_EOC)) {}
/* read result */
sample = (int)ADC1->DR;
/* unlock and power off device again */
done();
return sample;
}

View File

@ -1,31 +0,0 @@
# Compute CPU_LINE
LINE := $(shell echo $(CPU_MODEL) | tr 'a-z-' 'A-Z_' | sed -E -e 's/^STM32F([0-9][0-9][0-9])(.)(.)/\1 \2 \3/')
TYPE := $(word 1, $(LINE))
MODEL1 := $(word 2, $(LINE))
MODEL2 := $(word 3, $(LINE))
ifneq (, $(filter $(TYPE), 030 031 042 070))
ifneq (, $(filter $(MODEL2), 4))
CPU_LINE = STM32F$(TYPE)x4
else ifneq (, $(filter $(MODEL2), 6))
CPU_LINE = STM32F$(TYPE)x6
else ifneq (, $(filter $(MODEL2), 8))
CPU_LINE = STM32F$(TYPE)x8
else ifneq (, $(filter $(MODEL2), B))
CPU_LINE = STM32F$(TYPE)xB
else ifneq (, $(filter $(MODEL2), C))
CPU_LINE = STM32F$(TYPE)xC
endif
else ifneq (, $(filter $(TYPE), 051))
CPU_LINE = STM32F$(TYPE)x8
else ifneq (, $(filter $(TYPE), 071 072))
CPU_LINE = STM32F$(TYPE)xB
else ifneq (, $(filter $(TYPE), 091))
CPU_LINE = STM32F$(TYPE)xC
else
CPU_LINE = STM32F$(TYPE)xx
endif
ifeq ($(CPU_LINE), )
$(error Unsupported CPU)
endif

View File

@ -1,254 +0,0 @@
/*
* Copyright (C) 2014-2017 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.
*/
/**
* @ingroup cpu_stm32f0
* @{
*
* @file
* @brief Interrupt vector definitions
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include "vectors_cortexm.h"
/* define a local dummy handler as it needs to be in the same compilation unit
* as the alias definition */
void dummy_handler(void) {
dummy_handler_default();
}
/* STM32F0 specific interrupt vectors */
WEAK_DEFAULT void isr_adc1(void);
WEAK_DEFAULT void isr_adc1_comp(void);
WEAK_DEFAULT void isr_cec_can(void);
WEAK_DEFAULT void isr_dma1_ch1(void);
WEAK_DEFAULT void isr_dma1_ch2_3_dma2_ch1_2(void);
WEAK_DEFAULT void isr_dma1_ch4_7_dma2_ch3_5(void);
WEAK_DEFAULT void isr_dma1_channel1(void);
WEAK_DEFAULT void isr_dma1_channel2_3(void);
WEAK_DEFAULT void isr_dma1_channel4_5(void);
WEAK_DEFAULT void isr_dma1_channel4_5_6_7(void);
WEAK_DEFAULT void isr_exti(void);
WEAK_DEFAULT void isr_flash(void);
WEAK_DEFAULT void isr_i2c1(void);
WEAK_DEFAULT void isr_i2c2(void);
WEAK_DEFAULT void isr_pvd(void);
WEAK_DEFAULT void isr_pvd_vddio2(void);
WEAK_DEFAULT void isr_rcc(void);
WEAK_DEFAULT void isr_rcc_crs(void);
WEAK_DEFAULT void isr_rtc(void);
WEAK_DEFAULT void isr_spi1(void);
WEAK_DEFAULT void isr_spi2(void);
WEAK_DEFAULT void isr_tim14(void);
WEAK_DEFAULT void isr_tim15(void);
WEAK_DEFAULT void isr_tim16(void);
WEAK_DEFAULT void isr_tim17(void);
WEAK_DEFAULT void isr_tim1_brk_up_trg_com(void);
WEAK_DEFAULT void isr_tim1_cc(void);
WEAK_DEFAULT void isr_tim2(void);
WEAK_DEFAULT void isr_tim3(void);
WEAK_DEFAULT void isr_tim6(void);
WEAK_DEFAULT void isr_tim6_dac(void);
WEAK_DEFAULT void isr_tim7(void);
WEAK_DEFAULT void isr_tsc(void);
WEAK_DEFAULT void isr_usart1(void);
WEAK_DEFAULT void isr_usart2(void);
WEAK_DEFAULT void isr_usart3_4(void);
WEAK_DEFAULT void isr_usart3_6(void);
WEAK_DEFAULT void isr_usart3_8(void);
WEAK_DEFAULT void isr_usb(void);
WEAK_DEFAULT void isr_wwdg(void);
/* CPU specific interrupt vector table */
ISR_VECTOR(1) const isr_t vector_cpu[CPU_IRQ_NUMOF] = {
/* shared vectors for all family members */
[ 0] = isr_wwdg, /* [ 0] Window WatchDog Interrupt */
[ 2] = isr_rtc, /* [ 2] RTC Interrupt through EXTI Lines 17, 19 and 20 */
[ 3] = isr_flash, /* [ 3] FLASH global Interrupt */
[14] = isr_tim1_cc, /* [14] TIM1 Capture Compare Interrupt */
[16] = isr_tim3, /* [16] TIM3 global Interrupt */
[19] = isr_tim14, /* [19] TIM14 global Interrupt */
[21] = isr_tim16, /* [21] TIM16 global Interrupt */
[22] = isr_tim17, /* [22] TIM17 global Interrupt */
[25] = isr_spi1, /* [25] SPI1 global Interrupt */
#if defined(CPU_LINE_STM32F030x4)
[ 4] = isr_rcc, /* [ 4] RCC global Interrupt */
[ 5] = isr_exti, /* [ 5] EXTI Line 0 and 1 Interrupt */
[ 6] = isr_exti, /* [ 6] EXTI Line 2 and 3 Interrupt */
[ 7] = isr_exti, /* [ 7] EXTI Line 4 to 15 Interrupt */
[ 9] = isr_dma1_channel1, /* [ 9] DMA1 Channel 1 Interrupt */
[10] = isr_dma1_channel2_3, /* [10] DMA1 Channel 2 and Channel 3 Interrupt */
[11] = isr_dma1_channel4_5, /* [11] DMA1 Channel 4 and Channel 5 Interrupt */
[12] = isr_adc1, /* [12] ADC1 Interrupt */
[13] = isr_tim1_brk_up_trg_com, /* [13] TIM1 Break, Update, Trigger and Commutation Interrupt */
[23] = isr_i2c1, /* [23] I2C1 Event Interrupt */
[27] = isr_usart1, /* [27] USART1 global Interrupt */
#elif defined(CPU_LINE_STM32F030x8)
[ 4] = isr_rcc, /* [ 4] RCC global Interrupt */
[ 5] = isr_exti, /* [ 5] EXTI Line 0 and 1 Interrupt */
[ 6] = isr_exti, /* [ 6] EXTI Line 2 and 3 Interrupt */
[ 7] = isr_exti, /* [ 7] EXTI Line 4 to 15 Interrupt */
[ 9] = isr_dma1_channel1, /* [ 9] DMA1 Channel 1 Interrupt */
[10] = isr_dma1_channel2_3, /* [10] DMA1 Channel 2 and Channel 3 Interrupt */
[11] = isr_dma1_channel4_5, /* [11] DMA1 Channel 4 and Channel 5 Interrupt */
[12] = isr_adc1, /* [12] ADC1 Interrupt */
[13] = isr_tim1_brk_up_trg_com, /* [13] TIM1 Break, Update, Trigger and Commutation Interrupt */
[17] = isr_tim6, /* [17] TIM6 global Interrupt */
[20] = isr_tim15, /* [20] TIM15 global Interrupt */
[23] = isr_i2c1, /* [23] I2C1 Event Interrupt */
[24] = isr_i2c2, /* [24] I2C2 Event Interrupt */
[26] = isr_spi2, /* [26] SPI2 global Interrupt */
[27] = isr_usart1, /* [27] USART1 global Interrupt */
[28] = isr_usart2, /* [28] USART2 global Interrupt */
#elif defined(CPU_LINE_STM32F031x6)
[ 1] = isr_pvd, /* [ 1] PVD Interrupt through EXTI Lines 16 */
[ 4] = isr_rcc, /* [ 4] RCC global Interrupt */
[ 5] = isr_exti, /* [ 5] EXTI Line 0 and 1 Interrupt */
[ 6] = isr_exti, /* [ 6] EXTI Line 2 and 3 Interrupt */
[ 7] = isr_exti, /* [ 7] EXTI Line 4 to 15 Interrupt */
[ 9] = isr_dma1_channel1, /* [ 9] DMA1 Channel 1 Interrupt */
[10] = isr_dma1_channel2_3, /* [10] DMA1 Channel 2 and Channel 3 Interrupt */
[11] = isr_dma1_channel4_5, /* [11] DMA1 Channel 4 and Channel 5 Interrupt */
[12] = isr_adc1, /* [12] ADC1 Interrupt */
[13] = isr_tim1_brk_up_trg_com, /* [13] TIM1 Break, Update, Trigger and Commutation Interrupt */
[15] = isr_tim2, /* [15] TIM2 global Interrupt */
[23] = isr_i2c1, /* [23] I2C1 Event Interrupt & EXTI Line23 Interrupt (I2C1 wakeup) */
[27] = isr_usart1, /* [27] USART1 global Interrupt & EXTI Line25 Interrupt (USART1 wakeup) */
#elif defined(CPU_LINE_STM32F042x6)
[ 1] = isr_pvd_vddio2, /* [ 1] PVD & VDDIO2 Interrupts through EXTI Lines 16 and 31 */
[ 4] = isr_rcc_crs, /* [ 4] RCC & CRS Global Interrupts */
[ 5] = isr_exti, /* [ 5] EXTI Line 0 and 1 Interrupts */
[ 6] = isr_exti, /* [ 6] EXTI Line 2 and 3 Interrupts */
[ 7] = isr_exti, /* [ 7] EXTI Line 4 to 15 Interrupts */
[ 8] = isr_tsc, /* [ 8] Touch Sensing Controller Interrupts */
[ 9] = isr_dma1_channel1, /* [ 9] DMA1 Channel 1 Interrupt */
[10] = isr_dma1_channel2_3, /* [10] DMA1 Channel 2 and Channel 3 Interrupts */
[11] = isr_dma1_channel4_5, /* [11] DMA1 Channel 4 and Channel 5 Interrupts */
[12] = isr_adc1, /* [12] ADC1 Interrupt */
[13] = isr_tim1_brk_up_trg_com, /* [13] TIM1 Break, Update, Trigger and Commutation Interrupts */
[15] = isr_tim2, /* [15] TIM2 global Interrupt */
[23] = isr_i2c1, /* [23] I2C1 Event Interrupt & EXTI Line23 Interrupt (I2C1 wakeup) */
[26] = isr_spi2, /* [26] SPI2 global Interrupt */
[27] = isr_usart1, /* [27] USART1 global Interrupt & EXTI Line25 Interrupt (USART1 wakeup) */
[28] = isr_usart2, /* [28] USART2 global Interrupt */
[30] = isr_cec_can, /* [30] CEC and CAN global Interrupts & EXTI Line27 Interrupt */
[31] = isr_usb, /* [31] USB global Interrupts & EXTI Line18 Interrupt */
#elif defined(CPU_LINE_STM32F051x8)
[ 1] = isr_pvd, /* [ 1] PVD Interrupt through EXTI Lines 16 */
[ 4] = isr_rcc, /* [ 4] RCC global Interrupt */
[ 5] = isr_exti, /* [ 5] EXTI Line 0 and 1 Interrupts */
[ 6] = isr_exti, /* [ 6] EXTI Line 2 and 3 Interrupts */
[ 7] = isr_exti, /* [ 7] EXTI Line 4 to 15 Interrupts */
[ 8] = isr_tsc, /* [ 8] Touch Sensing Controller Interrupts */
[ 9] = isr_dma1_channel1, /* [ 9] DMA1 Channel 1 Interrupt */
[10] = isr_dma1_channel2_3, /* [10] DMA1 Channel 2 and Channel 3 Interrupts */
[11] = isr_dma1_channel4_5, /* [11] DMA1 Channel 4 and Channel 5 Interrupts */
[12] = isr_adc1_comp, /* [12] ADC1 and COMP interrupts (ADC interrupt combined with EXTI Lines 21 and 22 */
[13] = isr_tim1_brk_up_trg_com, /* [13] TIM1 Break, Update, Trigger and Commutation Interrupts */
[15] = isr_tim2, /* [15] TIM2 global Interrupt */
[17] = isr_tim6_dac, /* [17] TIM6 global and DAC channel underrun error Interrupts */
[20] = isr_tim15, /* [20] TIM15 global Interrupt */
[23] = isr_i2c1, /* [23] I2C1 Event Interrupt & EXTI Line23 Interrupt (I2C1 wakeup) */
[24] = isr_i2c2, /* [24] I2C2 Event Interrupt */
[26] = isr_spi2, /* [26] SPI2 global Interrupt */
[27] = isr_usart1, /* [27] USART1 global Interrupt & EXTI Line25 Interrupt (USART1 wakeup) */
[28] = isr_usart2, /* [28] USART2 global Interrupt */
[30] = isr_cec_can, /* [30] CEC and CAN global Interrupts & EXTI Line27 Interrupt */
#elif defined(CPU_LINE_STM32F070xB)
[ 4] = isr_rcc, /* [ 4] RCC global Interrupt */
[ 5] = isr_exti, /* [ 5] EXTI Line 0 and 1 Interrupt */
[ 6] = isr_exti, /* [ 6] EXTI Line 2 and 3 Interrupt */
[ 7] = isr_exti, /* [ 7] EXTI Line 4 to 15 Interrupt */
[ 9] = isr_dma1_channel1, /* [ 9] DMA1 Channel 1 Interrupt */
[10] = isr_dma1_channel2_3, /* [10] DMA1 Channel 2 and Channel 3 Interrupt */
[11] = isr_dma1_channel4_5, /* [11] DMA1 Channel 4 and Channel 5 Interrupt */
[12] = isr_adc1, /* [12] ADC1 Interrupt */
[13] = isr_tim1_brk_up_trg_com, /* [13] TIM1 Break, Update, Trigger and Commutation Interrupt */
[17] = isr_tim6, /* [17] TIM6 global Interrupt */
[18] = isr_tim7, /* [18] TIM7 global Interrupt */
[20] = isr_tim15, /* [20] TIM15 global Interrupt */
[23] = isr_i2c1, /* [23] I2C1 Event Interrupt & EXTI Line23 Interrupt (I2C1 wakeup) */
[24] = isr_i2c2, /* [24] I2C2 Event Interrupt */
[26] = isr_spi2, /* [26] SPI2 global Interrupt */
[27] = isr_usart1, /* [27] USART1 global Interrupt */
[28] = isr_usart2, /* [28] USART2 global Interrupt */
[29] = isr_usart3_4, /* [29] USART3 and USART4 global Interrupt */
[31] = isr_usb, /* [31] USB global Interrupt & EXTI Line18 Interrupt */
#elif defined(CPU_LINE_STM32F072xB)
[ 1] = isr_pvd_vddio2, /* [ 1] PVD & VDDIO2 Interrupt through EXTI Lines 16 and 31 */
[ 4] = isr_rcc_crs, /* [ 4] RCC & CRS global Interrupt */
[ 5] = isr_exti, /* [ 5] EXTI Line 0 and 1 Interrupt */
[ 6] = isr_exti, /* [ 6] EXTI Line 2 and 3 Interrupt */
[ 7] = isr_exti, /* [ 7] EXTI Line 4 to 15 Interrupt */
[ 8] = isr_tsc, /* [ 8] Touch Sensing Controller Interrupts */
[ 9] = isr_dma1_channel1, /* [ 9] DMA1 Channel 1 Interrupt */
[10] = isr_dma1_channel2_3, /* [10] DMA1 Channel 2 and Channel 3 Interrupt */
[11] = isr_dma1_channel4_5_6_7, /* [11] DMA1 Channel 4 to Channel 7 Interrupt */
[12] = isr_adc1_comp, /* [12] ADC1 and COMP interrupts (ADC interrupt combined with EXTI Lines 21 and 22 */
[13] = isr_tim1_brk_up_trg_com, /* [13] TIM1 Break, Update, Trigger and Commutation Interrupt */
[15] = isr_tim2, /* [15] TIM2 global Interrupt */
[17] = isr_tim6_dac, /* [17] TIM6 global and DAC channel underrun error Interrupt */
[18] = isr_tim7, /* [18] TIM7 global Interrupt */
[20] = isr_tim15, /* [20] TIM15 global Interrupt */
[23] = isr_i2c1, /* [23] I2C1 Event Interrupt & EXTI Line23 Interrupt (I2C1 wakeup) */
[24] = isr_i2c2, /* [24] I2C2 Event Interrupt */
[26] = isr_spi2, /* [26] SPI2 global Interrupt */
[27] = isr_usart1, /* [27] USART1 global Interrupt & EXTI Line25 Interrupt (USART1 wakeup) */
[28] = isr_usart2, /* [28] USART2 global Interrupt & EXTI Line26 Interrupt (USART2 wakeup) */
[29] = isr_usart3_4, /* [29] USART3 and USART4 global Interrupt */
[30] = isr_cec_can, /* [30] CEC and CAN global Interrupts & EXTI Line27 Interrupt */
[31] = isr_usb, /* [31] USB global Interrupt & EXTI Line18 Interrupt */
#elif defined(CPU_LINE_STM32F091xC)
[ 1] = isr_pvd_vddio2, /* [ 1] PVD & VDDIO2 Interrupts through EXTI Lines 16 and 31 */
[ 4] = isr_rcc_crs, /* [ 4] RCC & CRS global Interrupts */
[ 5] = isr_exti, /* [ 5] EXTI Line 0 and 1 Interrupts */
[ 6] = isr_exti, /* [ 6] EXTI Line 2 and 3 Interrupts */
[ 7] = isr_exti, /* [ 7] EXTI Line 4 to 15 Interrupts */
[ 8] = isr_tsc, /* [ 8] Touch Sensing Controller Interrupts */
[ 9] = isr_dma1_ch1, /* [ 9] DMA1 Channel 1 Interrupt */
[10] = isr_dma1_ch2_3_dma2_ch1_2,/* [10] DMA1 Channel 2 and 3 & DMA2 Channel 1 and 2 Interrupts */
[11] = isr_dma1_ch4_7_dma2_ch3_5,/* [11] DMA1 Channel 4 to 7 & DMA2 Channel 3 to 5 Interrupts */
[12] = isr_adc1_comp, /* [12] ADC, COMP1 and COMP2 Interrupts (EXTI Lines 21 and 22) */
[13] = isr_tim1_brk_up_trg_com, /* [13] TIM1 Break, Update, Trigger and Commutation Interrupts */
[15] = isr_tim2, /* [15] TIM2 global Interrupt */
[17] = isr_tim6_dac, /* [17] TIM6 global and DAC channel underrun error Interrupts */
[18] = isr_tim7, /* [18] TIM7 global Interrupt */
[20] = isr_tim15, /* [20] TIM15 global Interrupt */
[23] = isr_i2c1, /* [23] I2C1 Event Interrupt & EXTI Line23 Interrupt (I2C1 wakeup) */
[24] = isr_i2c2, /* [24] I2C2 Event Interrupt */
[26] = isr_spi2, /* [26] SPI2 global Interrupt */
[27] = isr_usart1, /* [27] USART1 global Interrupt & EXTI Line25 Interrupt (USART1 wakeup) */
[28] = isr_usart2, /* [28] USART2 global Interrupt & EXTI Line26 Interrupt (USART2 wakeup) */
[29] = isr_usart3_8, /* [29] USART3 to USART8 global Interrupts */
[30] = isr_cec_can, /* [30] CEC and CAN global Interrupts & EXTI Line27 Interrupt */
#elif defined(CPU_LINE_STM32F030xC)
[ 4] = isr_rcc, /* [ 4] RCC global Interrupt */
[ 5] = isr_exti, /* [ 5] EXTI Line 0 and 1 Interrupt */
[ 6] = isr_exti, /* [ 6] EXTI Line 2 and 3 Interrupt */
[ 7] = isr_exti, /* [ 7] EXTI Line 4 to 15 Interrupt */
[ 9] = isr_dma1_channel1, /* [ 9] DMA1 Channel 1 Interrupt */
[10] = isr_dma1_channel2_3, /* [10] DMA1 Channel 2 and Channel 3 Interrupt */
[11] = isr_dma1_channel4_5, /* [11] DMA1 Channel 4 and Channel 5 Interrupt */
[12] = isr_adc1, /* [12] ADC1 Interrupt */
[13] = isr_tim1_brk_up_trg_com, /* [13] TIM1 Break, Update, Trigger and Commutation Interrupt */
[17] = isr_tim6, /* [17] TIM6 global Interrupt */
[18] = isr_tim7, /* [18] TIM7 global Interrupt */
[20] = isr_tim15, /* [20] TIM15 global Interrupt */
[23] = isr_i2c1, /* [23] I2C1 Event Interrupt & EXTI Line23 Interrupt (I2C1 wakeup) */
[24] = isr_i2c2, /* [24] I2C2 Event Interrupt */
[26] = isr_spi2, /* [26] SPI2 global Interrupt */
[27] = isr_usart1, /* [27] USART1 global Interrupt */
[28] = isr_usart2, /* [28] USART2 global Interrupt */
[29] = isr_usart3_6, /* [29] USART3..6 global Interrupt */
#endif
};

View File

@ -1,10 +0,0 @@
# define the module that is build
MODULE = cpu
# add a list of subdirectories, that should also be build
DIRS += periph $(RIOTCPU)/cortexm_common $(RIOTCPU)/stm32_common
# (file triggers compiler bug. see #5775)
SRC_NOLTO += vectors.c
include $(RIOTBASE)/Makefile.base

View File

@ -1 +0,0 @@
include $(RIOTCPU)/stm32_common/Makefile.dep

View File

@ -1,10 +0,0 @@
CPU_ARCH = cortex-m3
CPU_FAM = stm32f1
FEATURES_PROVIDED += periph_flashpage
FEATURES_PROVIDED += periph_flashpage_raw
FEATURES_CONFLICT += periph_rtc:periph_rtt
FEATURES_CONFLICT_MSG += "On the STM32F1, the RTC and RTT map to the same hardware peripheral."
-include $(RIOTCPU)/stm32_common/Makefile.features

View File

@ -1,2 +0,0 @@
include $(RIOTCPU)/stm32_common/Makefile.include
include $(RIOTMAKE)/arch/cortexm.inc.mk

View File

@ -1,72 +0,0 @@
/*
* Copyright (C) 2013 INRIA
* Copyright (C) 2014 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.
*/
/**
* @defgroup cpu_stm32f1 STM32F1
* @ingroup cpu
* @brief CPU specific implementations for the STM32F1
* @{
*
* @file
* @brief Implementation specific CPU configuration options
*
* @author Alaeddine Weslati <alaeddine.weslati@intia.fr>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef CPU_CONF_H
#define CPU_CONF_H
#include "cpu_conf_common.h"
#include "vendor/stm32f1xx.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief ARM Cortex-M specific CPU configuration
* @{
*/
#define CPU_DEFAULT_IRQ_PRIO (1U)
#if defined(CPU_LINE_STM32F103xE)
#define CPU_IRQ_NUMOF (60U)
#else
#define CPU_IRQ_NUMOF (43U)
#endif
#define CPU_FLASH_BASE FLASH_BASE
/** @} */
/**
* @brief Flash page configuration
* @{
*/
#if defined(CPU_LINE_STM32F103xB)
#define FLASHPAGE_SIZE (1024U)
#elif defined(CPU_LINE_STM32F103xE)
#define FLASHPAGE_SIZE (2048U)
#endif
#define FLASHPAGE_NUMOF (STM32_FLASHSIZE / FLASHPAGE_SIZE)
/* The minimum block size which can be written is 2B. However, the erase
* block is always FLASHPAGE_SIZE.
*/
#define FLASHPAGE_RAW_BLOCKSIZE (2U)
/* Writing should be always 4 bytes aligned */
#define FLASHPAGE_RAW_ALIGNMENT (4U)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* CPU_CONF_H */
/** @} */

View File

@ -1,158 +0,0 @@
/*
* Copyright (C) 2015-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.
*/
/**
* @ingroup cpu_stm32f1
* @{
*
* @file
* @brief CPU specific definitions for internal peripheral handling
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef PERIPH_CPU_H
#define PERIPH_CPU_H
#include "periph_cpu_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Available number of ADC devices
*/
#define ADC_DEVS (2U)
/**
* @brief Starting address of the CPU ID
*/
#define CPUID_ADDR (0x1ffff7e8)
/**
* @brief All timers for the STM32F1 have 4 CC channels
*/
#define TIMER_CHANNELS (4U)
/**
* @brief All timers have a width of 16-bit
*/
#define TIMER_MAXVAL (0xffff)
/**
* @brief Generate GPIO mode bitfields
*
* We use 4 bit to determine the pin functions:
* - bit 4: ODR value
* - bit 2+3: in/out
* - bit 1: PU enable
* - bit 2: OD enable
*/
#define GPIO_MODE(mode, cnf, odr) (mode | (cnf << 2) | (odr << 4))
/**
* @brief Define the number of available PM modes
*/
#define PM_NUM_MODES (2U)
/**
* @brief Define the config flag for stop mode
*/
#define PM_STOP_CONFIG (PWR_CR_LPDS)
#ifndef DOXYGEN
/**
* @brief Override GPIO mode options
*
* We use 4 bit to encode CNF and MODE.
* @{
*/
#define HAVE_GPIO_MODE_T
typedef enum {
GPIO_IN = GPIO_MODE(0, 1, 0), /**< input w/o pull R */
GPIO_IN_PD = GPIO_MODE(0, 2, 0), /**< input with pull-down */
GPIO_IN_PU = GPIO_MODE(0, 2, 1), /**< input with pull-up */
GPIO_OUT = GPIO_MODE(3, 0, 0), /**< push-pull output */
GPIO_OD = GPIO_MODE(3, 1, 0), /**< open-drain w/o pull R */
GPIO_OD_PU = (0xff) /**< not supported by HW */
} gpio_mode_t;
/** @} */
#endif /* ndef DOXYGEN */
/**
* @brief Override values for pull register configuration
* @{
*/
#define HAVE_GPIO_PP_T
typedef enum {
GPIO_NOPULL = 4, /**< do not use internal pull resistors */
GPIO_PULLUP = 9, /**< enable internal pull-up resistor */
GPIO_PULLDOWN = 8 /**< enable internal pull-down resistor */
} gpio_pp_t;
/** @} */
#ifndef DOXYGEN
/**
* @brief Override flank configuration values
* @{
*/
#define HAVE_GPIO_FLANK_T
typedef enum {
GPIO_RISING = 1, /**< emit interrupt on rising flank */
GPIO_FALLING = 2, /**< emit interrupt on falling flank */
GPIO_BOTH = 3 /**< emit interrupt on both flanks */
} gpio_flank_t;
/** @} */
#endif /* ndef DOXYGEN */
/**
* @brief Available ports on the STM32F1 family
*/
enum {
PORT_A = 0, /**< port A */
PORT_B = 1, /**< port B */
PORT_C = 2, /**< port C */
PORT_D = 3, /**< port D */
PORT_E = 4, /**< port E */
PORT_F = 5, /**< port F */
PORT_G = 6, /**< port G */
};
/**
* @brief ADC channel configuration data
*/
typedef struct {
gpio_t pin; /**< pin connected to the channel */
uint8_t dev; /**< ADCx - 1 device used for the channel */
uint8_t chan; /**< CPU ADC channel connected to the pin */
} adc_conf_t;
/**
* @name Real time counter configuration
* @{
*/
#define RTT_IRQ_PRIO 1
#define RTT_DEV RTC
#define RTT_IRQ RTC_IRQn
#define RTT_ISR isr_rtc
#define RTT_MAX_VALUE (0xffffffff)
#define RTT_CLOCK_FREQUENCY (32768U) /* in Hz */
#define RTT_MIN_FREQUENCY (1U) /* in Hz */
/* RTC frequency of 32kHz is not recommended, see RM0008 Rev 20, p490 */
#define RTT_MAX_FREQUENCY (RTT_CLOCK_FREQUENCY / 2) /* in Hz */
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* PERIPH_CPU_H */
/** @} */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,212 +0,0 @@
/**
******************************************************************************
* @file stm32f1xx.h
* @author MCD Application Team
* @version V4.2.0
* @date 31-March-2017
* @brief CMSIS STM32F1xx Device Peripheral Access Layer Header File.
*
* The file is the unique include file that the application programmer
* is using in the C source code, usually in main.c. This file contains:
* - Configuration section that allows to select:
* - The STM32F1xx device used in the target application
* - To use or not the peripheral’s drivers in application code(i.e.
* code will be based on direct access to peripheral’s registers
* rather than drivers API), this option is controlled by
* "#define USE_HAL_DRIVER"
*
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32f1xx
* @{
*/
#ifndef __STM32F1XX_H
#define __STM32F1XX_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/** @addtogroup Library_configuration_section
* @{
*/
/**
* @brief STM32 Family
*/
#if !defined (STM32F1)
#define STM32F1
#endif /* STM32F1 */
/* Uncomment the line below according to the target STM32L device used in your
application
*/
#if !defined (STM32F100xB) && !defined (STM32F100xE) && !defined (STM32F101x6) && \
!defined (STM32F101xB) && !defined (STM32F101xE) && !defined (STM32F101xG) && !defined (STM32F102x6) && !defined (STM32F102xB) && !defined (STM32F103x6) && \
!defined (STM32F103xB) && !defined (STM32F103xE) && !defined (STM32F103xG) && !defined (STM32F105xC) && !defined (STM32F107xC)
/* #define STM32F100xB */ /*!< STM32F100C4, STM32F100R4, STM32F100C6, STM32F100R6, STM32F100C8, STM32F100R8, STM32F100V8, STM32F100CB, STM32F100RB and STM32F100VB */
/* #define STM32F100xE */ /*!< STM32F100RC, STM32F100VC, STM32F100ZC, STM32F100RD, STM32F100VD, STM32F100ZD, STM32F100RE, STM32F100VE and STM32F100ZE */
/* #define STM32F101x6 */ /*!< STM32F101C4, STM32F101R4, STM32F101T4, STM32F101C6, STM32F101R6 and STM32F101T6 Devices */
/* #define STM32F101xB */ /*!< STM32F101C8, STM32F101R8, STM32F101T8, STM32F101V8, STM32F101CB, STM32F101RB, STM32F101TB and STM32F101VB */
/* #define STM32F101xE */ /*!< STM32F101RC, STM32F101VC, STM32F101ZC, STM32F101RD, STM32F101VD, STM32F101ZD, STM32F101RE, STM32F101VE and STM32F101ZE */
/* #define STM32F101xG */ /*!< STM32F101RF, STM32F101VF, STM32F101ZF, STM32F101RG, STM32F101VG and STM32F101ZG */
/* #define STM32F102x6 */ /*!< STM32F102C4, STM32F102R4, STM32F102C6 and STM32F102R6 */
/* #define STM32F102xB */ /*!< STM32F102C8, STM32F102R8, STM32F102CB and STM32F102RB */
/* #define STM32F103x6 */ /*!< STM32F103C4, STM32F103R4, STM32F103T4, STM32F103C6, STM32F103R6 and STM32F103T6 */
/* #define STM32F103xB */ /*!< STM32F103C8, STM32F103R8, STM32F103T8, STM32F103V8, STM32F103CB, STM32F103RB, STM32F103TB and STM32F103VB */
/* #define STM32F103xE */ /*!< STM32F103RC, STM32F103VC, STM32F103ZC, STM32F103RD, STM32F103VD, STM32F103ZD, STM32F103RE, STM32F103VE and STM32F103ZE */
/* #define STM32F103xG */ /*!< STM32F103RF, STM32F103VF, STM32F103ZF, STM32F103RG, STM32F103VG and STM32F103ZG */
/* #define STM32F105xC */ /*!< STM32F105R8, STM32F105V8, STM32F105RB, STM32F105VB, STM32F105RC and STM32F105VC */
/* #define STM32F107xC */ /*!< STM32F107RB, STM32F107VB, STM32F107RC and STM32F107VC */
#endif
/* Tip: To avoid modifying this file each time you need to switch between these
devices, you can define the device in your toolchain compiler preprocessor.
*/
#if !defined (USE_HAL_DRIVER)
/**
* @brief Comment the line below if you will not use the peripherals drivers.
In this case, these drivers will not be included and the application code will
be based on direct access to peripherals registers
*/
/*#define USE_HAL_DRIVER */
#endif /* USE_HAL_DRIVER */
/**
* @brief CMSIS Device version number V4.2.0
*/
#define __STM32F1_CMSIS_VERSION_MAIN (0x04) /*!< [31:24] main version */
#define __STM32F1_CMSIS_VERSION_SUB1 (0x02) /*!< [23:16] sub1 version */
#define __STM32F1_CMSIS_VERSION_SUB2 (0x00) /*!< [15:8] sub2 version */
#define __STM32F1_CMSIS_VERSION_RC (0x00) /*!< [7:0] release candidate */
#define __STM32F1_CMSIS_VERSION ((__STM32F1_CMSIS_VERSION_MAIN << 24)\
|(__STM32F1_CMSIS_VERSION_SUB1 << 16)\
|(__STM32F1_CMSIS_VERSION_SUB2 << 8 )\
|(__STM32F1_CMSIS_VERSION_RC))
/**
* @}
*/
/** @addtogroup Device_Included
* @{
*/
#if defined(STM32F100xB)
#include "stm32f100xb.h"
#elif defined(STM32F100xE)
#include "stm32f100xe.h"
#elif defined(STM32F101x6)
#include "stm32f101x6.h"
#elif defined(STM32F101xB)
#include "stm32f101xb.h"
#elif defined(STM32F101xE)
#include "stm32f101xe.h"
#elif defined(STM32F101xG)
#include "stm32f101xg.h"
#elif defined(STM32F102x6)
#include "stm32f102x6.h"
#elif defined(STM32F102xB)
#include "stm32f102xb.h"
#elif defined(STM32F103x6)
#include "stm32f103x6.h"
#elif defined(STM32F103xB)
#include "stm32f103xb.h"
#elif defined(STM32F103xE)
#include "stm32f103xe.h"
#elif defined(STM32F103xG)
#include "stm32f103xg.h"
#elif defined(STM32F105xC)
#include "stm32f105xc.h"
#elif defined(STM32F107xC)
#include "stm32f107xc.h"
#else
#error "Please select first the target STM32F1xx device used in your application (in stm32f1xx.h file)"
#endif
/**
* @}
*/
/** @addtogroup Exported_macros
* @{
*/
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT))
#define READ_BIT(REG, BIT) ((REG) & (BIT))
#define CLEAR_REG(REG) ((REG) = (0x0))
#define WRITE_REG(REG, VAL) ((REG) = (VAL))
#define READ_REG(REG) ((REG))
#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))
#define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL)))
/**
* @}
*/
#if defined (USE_HAL_DRIVER)
#include "stm32f1xx_hal.h"
#endif /* USE_HAL_DRIVER */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __STM32F1xx_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -1 +0,0 @@
include $(RIOTMAKE)/periph.mk

View File

@ -1,167 +0,0 @@
/*
* Copyright (C) 2016 Engineering-Spirit
*
* 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 cpu_stm32f1
* @ingroup drivers_periph_adc
* @{
*
* @file
* @brief Low-level ADC driver implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Nick van IJzendoorn <nijzendoorn@engineering-spirit.nl>
*
* @}
*/
#include "cpu.h"
#include "mutex.h"
#include "periph/adc.h"
#include "periph_conf.h"
/**
* @brief Maximum allowed ADC clock speed
*/
#define MAX_ADC_SPEED (14000000U)
/**
* @brief Load the ADC configuration
*/
static const adc_conf_t adc_config[] = ADC_CONFIG;
/**
* @brief Allocate locks for all three available ADC devices
*/
static mutex_t locks[] = {
#if ADC_DEVS > 1
MUTEX_INIT,
#endif
#if ADC_DEVS > 2
MUTEX_INIT,
#endif
MUTEX_INIT
};
static inline ADC_TypeDef *dev(adc_t line)
{
return (ADC_TypeDef *)(ADC1_BASE + (adc_config[line].dev << 8));
}
static inline void prep(adc_t line)
{
mutex_lock(&locks[adc_config[line].dev]);
periph_clk_en(APB2, (RCC_APB2ENR_ADC1EN << adc_config[line].dev));
/* enable the ADC module */
dev(line)->CR2 |= ADC_CR2_ADON;
/* check if this channel is an internal ADC channel, if so
* enable the internal temperature and Vref */
if (adc_config[line].chan == 16 || adc_config[line].chan == 17) {
dev(line)->CR2 |= ADC_CR2_TSVREFE;
}
}
static inline void done(adc_t line)
{
/* disable the internal temperature and Vref */
dev(line)->CR2 &= ~ADC_CR2_TSVREFE;
/* disable the ADC module */
dev(line)->CR2 &= ~ADC_CR2_ADON;
periph_clk_dis(APB2, (RCC_APB2ENR_ADC1EN << adc_config[line].dev));
mutex_unlock(&locks[adc_config[line].dev]);
}
int adc_init(adc_t line)
{
uint32_t clk_div = 2;
/* check if the line is valid */
if (line >= ADC_NUMOF) {
return -1;
}
/* lock and power-on the device */
prep(line);
/* configure the pin */
if (adc_config[line].pin != GPIO_UNDEF) {
gpio_init_analog(adc_config[line].pin);
}
/* set clock prescaler to get the maximal possible ADC clock value */
for (clk_div = 2; clk_div < 8; clk_div += 2) {
if ((CLOCK_CORECLOCK / clk_div) <= MAX_ADC_SPEED) {
break;
}
}
RCC->CFGR &= ~(RCC_CFGR_ADCPRE);
RCC->CFGR |= ((clk_div / 2) - 1) << 14;
/* resets the selected ADC calibration registers */
dev(line)->CR2 |= ADC_CR2_RSTCAL;
/* check the status of RSTCAL bit */
while (dev(line)->CR2 & ADC_CR2_RSTCAL) {}
/* enable the selected ADC calibration process */
dev(line)->CR2 |= ADC_CR2_CAL;
/* wait for the calibration to have finished */
while (dev(line)->CR2 & ADC_CR2_CAL) {}
/* set all channels to maximum (239.5) cycles for best accuracy */
dev(line)->SMPR1 |= 0x00ffffff;
dev(line)->SMPR2 |= 0x3fffffff;
/* we want to sample one channel */
dev(line)->SQR1 = ADC_SQR1_L_0;
/* start sampling from software */
dev(line)->CR2 |= ADC_CR2_EXTTRIG | ADC_CR2_EXTSEL;
/* check if the internal channels are configured to use ADC1 */
if (adc_config[line].chan == 16 || adc_config[line].chan == 17) {
if (dev(line) != ADC1) {
return -3;
}
}
/* free the device again */
done(line);
return 0;
}
int32_t adc_sample(adc_t line, adc_res_t res)
{
int sample;
/* check if the linenel is valid */
if (line >= ADC_NUMOF) {
return -1;
}
/* check if resolution is applicable */
if (res != ADC_RES_12BIT) {
return -2;
}
/* lock and power on the ADC device */
prep(line);
/* set conversion channel */
dev(line)->SQR3 = adc_config[line].chan;
/* start conversion and wait for results */
dev(line)->CR2 |= ADC_CR2_SWSTART;
while (!(dev(line)->SR & ADC_SR_EOC)) {}
/* finally read sample and reset the STRT bit in the status register */
sample = (int)dev(line)->DR;
/* power off and unlock device again */
done(line);
return sample;
}

View File

@ -1,233 +0,0 @@
/*
* Copyright (C) 2014-2015 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.
*/
/**
* @ingroup cpu_stm32f1
* @ingroup drivers_periph_gpio
* @{
*
* @file
* @brief Low-level GPIO driver implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
*
* @}
*/
#include "cpu.h"
#include "board.h"
#include "periph/gpio.h"
#include "periph_cpu.h"
#include "periph_conf.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/**
* @brief Extract information from mode parameter
*/
#define MODE_MASK (0x0f)
#define ODR_POS (4U)
#ifdef MODULE_PERIPH_GPIO_IRQ
/**
* @brief Number of available external interrupt lines
*/
#define GPIO_ISR_CHAN_NUMOF (16U)
/**
* @brief Allocate memory for one callback and argument per EXTI channel
*/
static gpio_isr_ctx_t exti_ctx[GPIO_ISR_CHAN_NUMOF];
#endif /* MODULE_PERIPH_GPIO_IRQ */
/**
* @brief Extract the pin's port base address from the given pin identifier
*/
static inline GPIO_TypeDef *_port(gpio_t pin)
{
return (GPIO_TypeDef *)(pin & ~(0x0f));
}
/**
* @brief Extract the port number from the given pin identifier
*
* Isolating bits 10 to 13 of the port base addresses leads to unique port
* numbers.
*/
static inline int _port_num(gpio_t pin)
{
return (((pin >> 10) & 0x0f) - 2);
}
/**
* @brief Get the pin number from the pin identifier, encoded in the LSB 4 bit
*/
static inline int _pin_num(gpio_t pin)
{
return (pin & 0x0f);
}
int gpio_init(gpio_t pin, gpio_mode_t mode)
{
GPIO_TypeDef *port = _port(pin);
int pin_num = _pin_num(pin);
/* open-drain output with pull-up is not supported */
if (mode == GPIO_OD_PU) {
return -1;
}
/* enable the clock for the selected port */
periph_clk_en(APB2, (RCC_APB2ENR_IOPAEN << _port_num(pin)));
/* set pin mode */
port->CR[pin_num >> 3] &= ~(0xf << ((pin_num & 0x7) * 4));
port->CR[pin_num >> 3] |= ((mode & MODE_MASK) << ((pin_num & 0x7) * 4));
/* set ODR */
if (mode == GPIO_IN_PU)
port->ODR |= 1 << pin_num;
else
port->ODR &= ~(1 << pin_num);
return 0; /* all OK */
}
void gpio_init_af(gpio_t pin, gpio_af_t af)
{
int pin_num = _pin_num(pin);
GPIO_TypeDef *port = _port(pin);
/* enable the clock for the selected port */
periph_clk_en(APB2, (RCC_APB2ENR_IOPAEN << _port_num(pin)));
/* configure the pin */
port->CR[pin_num >> 3] &= ~(0xf << ((pin_num & 0x7) * 4));
port->CR[pin_num >> 3] |= (af << ((pin_num & 0x7) * 4));
}
void gpio_init_analog(gpio_t pin)
{
/* enable the GPIO port RCC */
periph_clk_en(APB2, (RCC_APB2ENR_IOPAEN << _port_num(pin)));
/* map the pin as analog input */
int pin_num = _pin_num(pin);
_port(pin)->CR[pin_num >= 8] &= ~(0xfl << (4 * (pin_num - ((pin_num >= 8) * 8))));
}
int gpio_read(gpio_t pin)
{
GPIO_TypeDef *port = _port(pin);
int pin_num = _pin_num(pin);
if (port->CR[pin_num >> 3] & (0x3 << ((pin_num & 0x7) << 2))) {
/* pin is output */
return (port->ODR & (1 << pin_num));
}
else {
/* or input */
return (port->IDR & (1 << pin_num));
}
}
void gpio_set(gpio_t pin)
{
_port(pin)->BSRR = (1 << _pin_num(pin));
}
void gpio_clear(gpio_t pin)
{
_port(pin)->BRR = (1 << _pin_num(pin));
}
void gpio_toggle(gpio_t pin)
{
if (gpio_read(pin)) {
gpio_clear(pin);
}
else {
gpio_set(pin);
}
}
void gpio_write(gpio_t pin, int value)
{
if (value) {
_port(pin)->BSRR = (1 << _pin_num(pin));
}
else {
_port(pin)->BRR = (1 << _pin_num(pin));
}
}
#ifdef MODULE_PERIPH_GPIO_IRQ
int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
gpio_cb_t cb, void *arg)
{
int pin_num = _pin_num(pin);
/* disable interrupts on the channel we want to edit (just in case) */
EXTI->IMR &= ~(1 << pin_num);
/* configure pin as input */
gpio_init(pin, mode);
/* set callback */
exti_ctx[pin_num].cb = cb;
exti_ctx[pin_num].arg = arg;
/* enable alternate function clock for the GPIO module */
periph_clk_en(APB2, RCC_APB2ENR_AFIOEN);
/* configure the EXTI channel */
AFIO->EXTICR[pin_num >> 2] &= ~(0xf << ((pin_num & 0x3) * 4));
AFIO->EXTICR[pin_num >> 2] |= (_port_num(pin) << ((pin_num & 0x3) * 4));
/* configure the active flank */
EXTI->RTSR &= ~(1 << pin_num);
EXTI->RTSR |= ((flank & 0x1) << pin_num);
EXTI->FTSR &= ~(1 << pin_num);
EXTI->FTSR |= ((flank >> 1) << pin_num);
/* active global interrupt for the selected port */
if (pin_num < 5) {
NVIC_EnableIRQ(EXTI0_IRQn + pin_num);
}
else if (pin_num < 10) {
NVIC_EnableIRQ(EXTI9_5_IRQn);
}
else {
NVIC_EnableIRQ(EXTI15_10_IRQn);
}
/* clear event mask */
EXTI->EMR &= ~(1 << pin_num);
/* unmask the pins interrupt channel */
EXTI->IMR |= (1 << pin_num);
return 0;
}
void gpio_irq_enable(gpio_t pin)
{
EXTI->IMR |= (1 << _pin_num(pin));
}
void gpio_irq_disable(gpio_t pin)
{
EXTI->IMR &= ~(1 << _pin_num(pin));
}
void isr_exti(void)
{
/* only generate interrupts against lines which have their IMR set */
uint32_t pending_isr = (EXTI->PR & EXTI->IMR);
for (unsigned i = 0; i < GPIO_ISR_CHAN_NUMOF; i++) {
if (pending_isr & (1 << i)) {
EXTI->PR = (1 << i); /* clear by writing a 1 */
exti_ctx[i].cb(exti_ctx[i].arg);
}
}
cortexm_isr_end();
}
#endif /* MODULE_PERIPH_GPIO_IRQ */

View File

@ -1,261 +0,0 @@
/*
* Copyright (C) 2019 Alexei Bezborodov
*
* 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 cpu_stm32f1
* @{
* @file
* @brief Low-level RTC driver implementation
*
* @author Alexei Bezborodov <alexeibv+riotos@narod.ru>
* @}
*/
#include <time.h>
#include "cpu.h"
#include "periph/rtc.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define EXTI_IMR_BIT (EXTI_IMR_MR17)
#define EXTI_FTSR_BIT (EXTI_FTSR_TR17)
#define EXTI_RTSR_BIT (EXTI_RTSR_TR17)
#define EXTI_PR_BIT (EXTI_PR_PR17)
static struct {
rtc_alarm_cb_t cb; /**< callback called from RTC interrupt */
void *arg; /**< argument passed to the callback */
} isr_ctx;
static void _rtc_enter_config_mode(void)
{
/* disable backup domain write protection */
PWR->CR |= PWR_CR_DBP;
/* wait until the RTOFF bit is 1 (no RTC register writes ongoing). */
while ((RTC->CRL & RTC_CRL_RTOFF) == 0) {}
/* enter configuration mode. */
RTC->CRL |= RTC_CRL_CNF;
}
static void _rtc_exit_config_mode(void)
{
/* exit configuration mode. */
RTC->CRL &= ~RTC_CRL_CNF;
/* wait until the RTOFF bit is 1 (our RTC register write finished). */
while ((RTC->CRL & RTC_CRL_RTOFF) == 0) {}
/* disable backup domain write protection */
PWR->CR &= ~PWR_CR_DBP;
}
static bool _is_rtc_enable(void)
{
return ((RCC->BDCR & RCC_BDCR_RTCEN) == RCC_BDCR_RTCEN);
}
static void _rtc_config(void)
{
DEBUG("[RTC] config\n");
/* enable APB1 clocks */
RCC->APB1ENR |= RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN;
/* disable backup domain write protection */
PWR->CR |= PWR_CR_DBP;
/* resets the entire backup domain */
RCC->BDCR |= RCC_BDCR_BDRST;
/* reset not activated */
RCC->BDCR &= ~RCC_BDCR_BDRST;
/* oscillator clock used as RTC clock */
RCC->BDCR |= RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL_LSE;
/* turn on LSE crystal */
RCC->BDCR |= RCC_BDCR_LSEON;
while ((RCC->BDCR & RCC_BDCR_LSEON) != RCC_BDCR_LSEON) {}
/* calibration clock from 0 to 0x7F */
BKP->RTCCR |= 0;
/* second interrupt is disabled. */
RTC->CRH &= ~RTC_CRH_SECIE;
_rtc_enter_config_mode();
/* if the input clock frequency (fRTCCLK) is 32.768 kHz, write 7FFFh in this register to get a signal period of 1 second. */
RTC->PRLH = 0;
RTC->PRLL = 0x7FFF;
_rtc_exit_config_mode();
/* wait registers synchronize flag */
RTC->CRL &= (uint16_t)~RTC_CRL_RSF;
while((RTC->CRL & RTC_CRL_RSF) != RTC_CRL_RSF) {}
/* disable backup domain write protection */
PWR->CR &= ~PWR_CR_DBP;
/* configure the EXTI channel, as RTC interrupts are routed through it.
* Needs to be configured to trigger on rising edges. */
EXTI->FTSR &= ~(EXTI_FTSR_BIT);
EXTI->RTSR |= EXTI_RTSR_BIT;
EXTI->IMR |= EXTI_IMR_BIT;
EXTI->PR |= EXTI_PR_BIT;
/* enable global RTC interrupt */
NVIC_EnableIRQ(RTC_Alarm_IRQn);
}
static uint32_t _rtc_get_time(void)
{
return (RTC->CNTH << 16) | RTC->CNTL;
}
static void _rtc_set_time(uint32_t counter_val)
{
_rtc_enter_config_mode();
RTC->CNTH = (counter_val & 0xffff0000) >> 16;
RTC->CNTL = counter_val & 0x0000ffff;
_rtc_exit_config_mode();
}
void rtc_init(void)
{
/* save current time if RTC already works */
bool is_rtc_enable = _is_rtc_enable();
uint32_t cur_time = 0;
if (is_rtc_enable) {
cur_time = _rtc_get_time();
}
/* config RTC */
_rtc_config();
/* restore current time after config */
if (is_rtc_enable) {
_rtc_set_time(cur_time);
}
}
int rtc_set_time(struct tm *time)
{
uint32_t timestamp = rtc_mktime(time);
_rtc_set_time(timestamp);
DEBUG("%s timestamp=%"PRIu32"\n", __func__, timestamp);
return 0;
}
int rtc_get_time(struct tm *time)
{
uint32_t timestamp = _rtc_get_time();
rtc_localtime(timestamp, time);
DEBUG("%s timestamp=%"PRIu32"\n", __func__, timestamp);
return 0;
}
static void _rtc_enable_alarm(void)
{
/* clear alarm flag */
RTC->CRL &= ~RTC_CRL_ALRF;
_rtc_enter_config_mode();
RTC->CRH |= (RTC_CRH_ALRIE);
_rtc_exit_config_mode();
}
static void _rtc_disable_alarm(void)
{
_rtc_enter_config_mode();
RTC->CRH &= ~RTC_CRH_ALRIE;
_rtc_exit_config_mode();
}
static uint32_t _rtc_get_alarm_time(void)
{
return (RTC->ALRH << 16) | RTC->ALRL;
}
static void _rtc_set_alarm_time(uint32_t alarm_time)
{
_rtc_enter_config_mode();
RTC->ALRL = (alarm_time & 0x0000ffff);
RTC->ALRH = (alarm_time & 0xffff0000) >> 16;
_rtc_exit_config_mode();
}
int rtc_set_alarm(struct tm *time, rtc_alarm_cb_t cb, void *arg)
{
uint32_t timestamp = rtc_mktime(time);
/* disable existing alarm (if enabled) */
rtc_clear_alarm();
/* save callback and argument */
isr_ctx.cb = cb;
isr_ctx.arg = arg;
/* set wakeup time */
_rtc_set_alarm_time(timestamp);
/* enable Alarm */
_rtc_enable_alarm();
DEBUG("%s timestamp=%"PRIu32"\n", __func__, timestamp);
return 0;
}
int rtc_get_alarm(struct tm *time)
{
uint32_t timestamp = _rtc_get_alarm_time();
rtc_localtime(timestamp, time);
DEBUG("%s timestamp=%"PRIu32"\n", __func__, timestamp);
return 0;
}
void rtc_clear_alarm(void)
{
_rtc_disable_alarm();
isr_ctx.cb = NULL;
isr_ctx.arg = NULL;
}
void rtc_poweron(void)
{
/* RTC is always on */
return;
}
void rtc_poweroff(void)
{
/* RTC is always on */
return;
}
void isr_rtc_alarm(void)
{
if (RTC->CRL & RTC_CRL_ALRF) {
if (isr_ctx.cb != NULL) {
isr_ctx.cb(isr_ctx.arg);
}
RTC->CRL &= ~RTC_CRL_ALRF;
}
EXTI->PR |= EXTI_PR_BIT;
cortexm_isr_end();
}

View File

@ -1,199 +0,0 @@
/*
* Copyright (C) 2014 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.
*/
/**
* @ingroup cpu_stm32f1
* @ingroup drivers_periph_rtt
* @{
*
* @file
* @brief Low-level RTT driver implementation
*
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
*
* @}
*/
#include "cpu.h"
#include "periph/rtt.h"
#include "periph_conf.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define RTT_PRESCALER ((RTT_CLOCK_FREQUENCY / RTT_FREQUENCY) - 1 )
#define RTT_FLAG_RTOFF ((uint16_t)0x0020) /**< RTC Operation OFF flag */
#define RTT_FLAG_RSF ((uint16_t)0x0008) /**< Registers Synchronized flag */
#define RTT_FLAG_OW ((uint16_t)0x0004) /**< Overflow flag */
#define RTT_FLAG_ALR ((uint16_t)0x0002) /**< Alarm flag */
#define RTT_FLAG_SEC ((uint16_t)0x0001) /**< Second flag */
static inline void _rtt_enter_config_mode(void);
static inline void _rtt_leave_config_mode(void);
/*
* callback and argument for an active alarm
*/
static rtt_cb_t alarm_cb;
static void *alarm_arg;
/*
* callback and argument for overflow callback
*/
static rtt_cb_t overflow_cb;
static void *overflow_arg;
void rtt_init(void)
{
rtt_poweron();
/* configure interrupt */
NVIC_SetPriority(RTT_IRQ, RTT_IRQ_PRIO);
NVIC_EnableIRQ(RTT_IRQ);
/* clear RSF flag */
RTT_DEV->CRL &= ~(RTT_FLAG_RSF);
_rtt_enter_config_mode();
/* Reset RTC counter MSB word */
RTT_DEV->CNTH = 0x0000;
/* Set RTC counter LSB word */
RTT_DEV->CNTL = 0x0000;
/* set prescaler */
RTT_DEV->PRLH = ((RTT_PRESCALER>>16)&0x000f);
RTT_DEV->PRLL = (RTT_PRESCALER&0xffff);
_rtt_leave_config_mode();
}
void rtt_set_overflow_cb(rtt_cb_t cb, void *arg)
{
overflow_cb = cb;
overflow_arg = arg;
_rtt_enter_config_mode();
/* Enable overflow interrupt */
RTT_DEV->CRH |= RTC_CRH_OWIE;
_rtt_leave_config_mode();
}
void rtt_clear_overflow_cb(void)
{
_rtt_enter_config_mode();
/* Clear overflow interrupt */
RTT_DEV->CRH &= ~(RTC_CRH_OWIE);
_rtt_leave_config_mode();
}
uint32_t rtt_get_counter(void)
{
/* wait for synchronization */
while (!(RTT_DEV->CRL & RTT_FLAG_RSF)) {}
return (((uint32_t)RTT_DEV->CNTH << 16 ) | (uint32_t)(RTT_DEV->CNTL));
}
void rtt_set_counter(uint32_t counter)
{
_rtt_enter_config_mode();
/* Set RTC counter MSB word */
RTT_DEV->CNTH = counter >> 16;
/* Set RTC counter LSB word */
RTT_DEV->CNTL = (counter & 0xffff);
_rtt_leave_config_mode();
}
uint32_t rtt_get_alarm(void)
{
/* wait for synchronization */
while (!(RTT_DEV->CRL & RTT_FLAG_RSF)) {}
return (((uint32_t)RTT_DEV->ALRH << 16 ) | (uint32_t)(RTT_DEV->ALRL));
}
void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg)
{
_rtt_enter_config_mode();
/* Set the alarm MSB word */
RTT_DEV->ALRH = alarm >> 16;
/* Set the alarm LSB word */
RTT_DEV->ALRL = (alarm & 0xffff);
/* Enable alarm interrupt */
RTT_DEV->CRH |= RTC_CRH_ALRIE;
_rtt_leave_config_mode();
alarm_cb = cb;
alarm_arg = arg;
}
void rtt_clear_alarm(void)
{
_rtt_enter_config_mode();
/* Disable alarm interrupt */
RTT_DEV->CRH &= ~RTC_CRH_ALRIE;
/* Set the ALARM MSB word to reset value */
RTT_DEV->ALRH = 0xffff;
/* Set the ALARM LSB word to reset value */
RTT_DEV->ALRL = 0xffff;
_rtt_leave_config_mode();
}
void rtt_poweron(void)
{
periph_clk_en(APB1, RCC_APB1ENR_BKPEN); /* enable BKP, Clock */
/* RTC clock source configuration */
PWR->CR |= PWR_CR_DBP; /* Allow access to BKP Domain */
RCC->BDCR |= RCC_BDCR_LSEON; /* Enable LSE OSC */
while(!(RCC->BDCR & RCC_BDCR_LSERDY)) {} /* Wait till LSE is ready */
RCC->BDCR |= RCC_BDCR_RTCSEL_LSE; /* Select the RTC Clock Source */
RCC->BDCR |= RCC_BDCR_RTCEN; /* enable RTC */
}
void rtt_poweroff(void)
{
PWR->CR |= PWR_CR_DBP; /* Allow access to BKP Domain */
RCC->BDCR &= ~RCC_BDCR_RTCEN; /* disable RTC */
periph_clk_dis(APB1, RCC_APB1ENR_BKPEN); /* disable BKP, Clock */
}
static inline void _rtt_enter_config_mode(void)
{
/* Loop until RTOFF flag is set */
while (!(RTT_DEV->CRL & RTT_FLAG_RTOFF)) {}
/* enter configuration mode */
RTT_DEV->CRL |= RTC_CRL_CNF;
}
static inline void _rtt_leave_config_mode(void)
{
/* leave configuration mode */
RTT_DEV->CRL &= ~RTC_CRL_CNF;
/* Loop until RTOFF flag is set */
while (!(RTT_DEV->CRL & RTT_FLAG_RTOFF)) {}
}
void RTT_ISR(void)
{
if (RTT_DEV->CRL & RTC_CRL_ALRF) {
RTT_DEV->CRL &= ~(RTC_CRL_ALRF);
alarm_cb(alarm_arg);
}
if (RTT_DEV->CRL & RTC_CRL_OWF) {
RTT_DEV->CRL &= ~(RTC_CRL_OWF);
overflow_cb(overflow_arg);
}
cortexm_isr_end();
}

View File

@ -1,31 +0,0 @@
# Compute CPU_LINE
LINE := $(shell echo $(CPU_MODEL) | tr 'a-z-' 'A-Z_' | sed -E -e 's/^STM32F([0-9][0-9][0-9])(.)(.)/\1 \2 \3/')
TYPE := $(word 1, $(LINE))
MODEL1 := $(word 2, $(LINE))
MODEL2 := $(word 3, $(LINE))
ifneq (, $(filter $(TYPE), 100))
ifneq (, $(filter $(MODEL2), 4 6 8 B))
CPU_LINE = STM32F$(TYPE)xB
else ifneq (, $(filter $(MODEL2), C D E))
CPU_LINE = STM32F$(TYPE)xE
else
$(error Unsuported CPU)
endif
else ifneq (, $(filter $(TYPE), 101 102 103))
ifneq (, $(filter $(MODEL2), 4 6))
CPU_LINE = STM32F$(TYPE)x6
else ifneq (, $(filter $(MODEL2), 8 B))
CPU_LINE = STM32F$(TYPE)xB
else ifneq (, $(filter $(MODEL2), C D E))
CPU_LINE = STM32F$(TYPE)xE
else ifneq (, $(filter $(MODEL2), F G))
CPU_LINE = STM32F$(TYPE)xG
else
$(error Unsuported CPU)
endif
else ifneq (, $(filter $(TYPE), 105 107))
CPU_LINE = STM32F$(TYPE)xC
else
$(error Unsuported CPU)
endif

View File

@ -1,152 +0,0 @@
/*
* Copyright (C) 2014-2017 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.
*/
/**
* @ingroup cpu_stm32f1
* @{
*
* @file
* @brief Interrupt vector definitions
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
*
* @}
*/
#include "vectors_cortexm.h"
/* define a local dummy handler as it needs to be in the same compilation unit
* as the alias definition */
void dummy_handler(void) {
dummy_handler_default();
}
/* STM32F1 specific interrupt vectors */
WEAK_DEFAULT void isr_adc1_2(void);
WEAK_DEFAULT void isr_adc3(void);
WEAK_DEFAULT void isr_can1_rx1(void);
WEAK_DEFAULT void isr_can1_sce(void);
WEAK_DEFAULT void isr_dma1_channel1(void);
WEAK_DEFAULT void isr_dma1_channel2(void);
WEAK_DEFAULT void isr_dma1_channel3(void);
WEAK_DEFAULT void isr_dma1_channel4(void);
WEAK_DEFAULT void isr_dma1_channel5(void);
WEAK_DEFAULT void isr_dma1_channel6(void);
WEAK_DEFAULT void isr_dma1_channel7(void);
WEAK_DEFAULT void isr_dma2_channel1(void);
WEAK_DEFAULT void isr_dma2_channel2(void);
WEAK_DEFAULT void isr_dma2_channel3(void);
WEAK_DEFAULT void isr_dma2_channel4_5(void);
WEAK_DEFAULT void isr_exti(void);
WEAK_DEFAULT void isr_flash(void);
WEAK_DEFAULT void isr_fsmc(void);
WEAK_DEFAULT void isr_i2c1_er(void);
WEAK_DEFAULT void isr_i2c1_ev(void);
WEAK_DEFAULT void isr_i2c2_er(void);
WEAK_DEFAULT void isr_i2c2_ev(void);
WEAK_DEFAULT void isr_pvd(void);
WEAK_DEFAULT void isr_rcc(void);
WEAK_DEFAULT void isr_rtc(void);
WEAK_DEFAULT void isr_rtc_alarm(void);
WEAK_DEFAULT void isr_sdio(void);
WEAK_DEFAULT void isr_spi1(void);
WEAK_DEFAULT void isr_spi2(void);
WEAK_DEFAULT void isr_spi3(void);
WEAK_DEFAULT void isr_tamper(void);
WEAK_DEFAULT void isr_tim1_brk(void);
WEAK_DEFAULT void isr_tim1_cc(void);
WEAK_DEFAULT void isr_tim1_trg_com(void);
WEAK_DEFAULT void isr_tim1_up(void);
WEAK_DEFAULT void isr_tim2(void);
WEAK_DEFAULT void isr_tim3(void);
WEAK_DEFAULT void isr_tim4(void);
WEAK_DEFAULT void isr_tim5(void);
WEAK_DEFAULT void isr_tim6(void);
WEAK_DEFAULT void isr_tim7(void);
WEAK_DEFAULT void isr_tim8_brk(void);
WEAK_DEFAULT void isr_tim8_cc(void);
WEAK_DEFAULT void isr_tim8_trg_com(void);
WEAK_DEFAULT void isr_tim8_up(void);
WEAK_DEFAULT void isr_uart4(void);
WEAK_DEFAULT void isr_uart5(void);
WEAK_DEFAULT void isr_usart1(void);
WEAK_DEFAULT void isr_usart2(void);
WEAK_DEFAULT void isr_usart3(void);
WEAK_DEFAULT void isr_usb_hp_can1_tx(void);
WEAK_DEFAULT void isr_usb_lp_can1_rx0(void);
WEAK_DEFAULT void isr_usbwakeup(void);
WEAK_DEFAULT void isr_wwdg(void);
/* CPU specific interrupt vector table */
ISR_VECTOR(1) const isr_t vector_cpu[CPU_IRQ_NUMOF] = {
/* shared vectors for all family members */
[ 0] = isr_wwdg, /* [ 0] Window WatchDog Interrupt */
[ 1] = isr_pvd, /* [ 1] PVD through EXTI Line detection Interrupt */
[ 2] = isr_tamper, /* [ 2] Tamper Interrupt */
[ 3] = isr_rtc, /* [ 3] RTC global Interrupt */
[ 4] = isr_flash, /* [ 4] FLASH global Interrupt */
[ 5] = isr_rcc, /* [ 5] RCC global Interrupt */
[ 6] = isr_exti, /* [ 6] EXTI Line0 Interrupt */
[ 7] = isr_exti, /* [ 7] EXTI Line1 Interrupt */
[ 8] = isr_exti, /* [ 8] EXTI Line2 Interrupt */
[ 9] = isr_exti, /* [ 9] EXTI Line3 Interrupt */
[10] = isr_exti, /* [10] EXTI Line4 Interrupt */
[11] = isr_dma1_channel1, /* [11] DMA1 Channel 1 global Interrupt */
[12] = isr_dma1_channel2, /* [12] DMA1 Channel 2 global Interrupt */
[13] = isr_dma1_channel3, /* [13] DMA1 Channel 3 global Interrupt */
[14] = isr_dma1_channel4, /* [14] DMA1 Channel 4 global Interrupt */
[15] = isr_dma1_channel5, /* [15] DMA1 Channel 5 global Interrupt */
[16] = isr_dma1_channel6, /* [16] DMA1 Channel 6 global Interrupt */
[17] = isr_dma1_channel7, /* [17] DMA1 Channel 7 global Interrupt */
[18] = isr_adc1_2, /* [18] ADC1 and ADC2 global Interrupt */
[19] = isr_usb_hp_can1_tx, /* [19] USB Device High Priority or CAN1 TX Interrupts */
[20] = isr_usb_lp_can1_rx0, /* [20] USB Device Low Priority or CAN1 RX0 Interrupts */
[21] = isr_can1_rx1, /* [21] CAN1 RX1 Interrupt */
[22] = isr_can1_sce, /* [22] CAN1 SCE Interrupt */
[23] = isr_exti, /* [23] External Line[9:5] Interrupts */
[24] = isr_tim1_brk, /* [24] TIM1 Break Interrupt */
[25] = isr_tim1_up, /* [25] TIM1 Update Interrupt */
[26] = isr_tim1_trg_com, /* [26] TIM1 Trigger and Commutation Interrupt */
[27] = isr_tim1_cc, /* [27] TIM1 Capture Compare Interrupt */
[28] = isr_tim2, /* [28] TIM2 global Interrupt */
[29] = isr_tim3, /* [29] TIM3 global Interrupt */
[30] = isr_tim4, /* [30] TIM4 global Interrupt */
[31] = isr_i2c1_ev, /* [31] I2C1 Event Interrupt */
[32] = isr_i2c1_er, /* [32] I2C1 Error Interrupt */
[33] = isr_i2c2_ev, /* [33] I2C2 Event Interrupt */
[34] = isr_i2c2_er, /* [34] I2C2 Error Interrupt */
[35] = isr_spi1, /* [35] SPI1 global Interrupt */
[36] = isr_spi2, /* [36] SPI2 global Interrupt */
[37] = isr_usart1, /* [37] USART1 global Interrupt */
[38] = isr_usart2, /* [38] USART2 global Interrupt */
[39] = isr_usart3, /* [39] USART3 global Interrupt */
[40] = isr_exti, /* [40] External Line[15:10] Interrupts */
[41] = isr_rtc_alarm, /* [41] RTC Alarm through EXTI Line Interrupt */
[42] = isr_usbwakeup, /* [42] USB Device WakeUp from suspend through EXTI Line Interrupt */
#if defined(CPU_LINE_STM32F103xE)
[43] = isr_tim8_brk, /* [43] TIM8 Break Interrupt */
[44] = isr_tim8_up, /* [44] TIM8 Update Interrupt */
[45] = isr_tim8_trg_com, /* [45] TIM8 Trigger and Commutation Interrupt */
[46] = isr_tim8_cc, /* [46] TIM8 Capture Compare Interrupt */
[47] = isr_adc3, /* [47] ADC3 global Interrupt */
[48] = isr_fsmc, /* [48] FSMC global Interrupt */
[49] = isr_sdio, /* [49] SDIO global Interrupt */
[50] = isr_tim5, /* [50] TIM5 global Interrupt */
[51] = isr_spi3, /* [51] SPI3 global Interrupt */
[52] = isr_uart4, /* [52] UART4 global Interrupt */
[53] = isr_uart5, /* [53] UART5 global Interrupt */
[54] = isr_tim6, /* [54] TIM6 global Interrupt */
[55] = isr_tim7, /* [55] TIM7 global Interrupt */
[56] = isr_dma2_channel1, /* [56] DMA2 Channel 1 global Interrupt */
[57] = isr_dma2_channel2, /* [57] DMA2 Channel 2 global Interrupt */
[58] = isr_dma2_channel3, /* [58] DMA2 Channel 3 global Interrupt */
[59] = isr_dma2_channel4_5, /* [59] DMA2 Channel 4 and Channel 5 global Interrupt */
#endif
};

View File

@ -1,7 +0,0 @@
# define the module that is build
MODULE = cpu
# add a list of subdirectories, that should also be build
DIRS = periph $(RIOTCPU)/cortexm_common $(RIOTCPU)/stm32_common
include $(RIOTBASE)/Makefile.base

View File

@ -1 +0,0 @@
include $(RIOTCPU)/stm32_common/Makefile.dep

View File

@ -1,7 +0,0 @@
CPU_ARCH = cortex-m3
CPU_FAM = stm32f2
FEATURES_PROVIDED += periph_hwrng
FEATURES_PROVIDED += cortexm_mpu
-include $(RIOTCPU)/stm32_common/Makefile.features

View File

@ -1,20 +0,0 @@
# STM32F2 uses sectors instead of pages, where the minimum sector length is 16KB
# (the first sector), therefore RIOTBOOT_LEN must be 16KB to cover a whole sector.
RIOTBOOT_LEN ?= 0x4000
# CPU_IRQ_NUMOF for STM32F2 boards is < 81+16 so (97*4 bytes = 388 bytes ~= 0x200)
# RIOTBOOT_HDR_LEN can be set to 0x200.
# Details on alignment requirements for M3 in `cpu/cortexm_common/Makefile.include`.
RIOTBOOT_HDR_LEN ?= 0x200
# Sectors don't have the same length. Per bank there can be up to 12 sectors. The
# first 4 sectors are 16kB long, the 5th is 64kB and the remaining 7 are 128kB.
# Since flash can only be erased by sector, slots can't overlap over sectors.
# The most efficient layout comes from removing RIOTBOOT_LEN twice, once at the
# start of the flash for the bootloader, and a second time at the end of the
# flash, to get evenly sized and distributed slots.
SLOT0_LEN ?= $(shell printf "0x%x" $$((($(ROM_LEN:%K=%*1024)-2*$(RIOTBOOT_LEN)) / $(NUM_SLOTS))))
SLOT1_LEN ?= $(SLOT0_LEN)
include $(RIOTCPU)/stm32_common/Makefile.include
include $(RIOTMAKE)/arch/cortexm.inc.mk

View File

@ -1,46 +0,0 @@
/*
* Copyright (C) 2015 Engineering-Spirit
*
* 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.
*/
/**
* @defgroup cpu_stm32f2 STM32F2
* @ingroup cpu
* @brief CPU specific implementations for the STM32F2
* @{
*
* @file
* @brief Implementation specific CPU configuration options
*
* @author Nick v. IJzendoorn <nijzendoorn@engineering-spirit.nl
*/
#ifndef CPU_CONF_H
#define CPU_CONF_H
#include "cpu_conf_common.h"
#include "vendor/stm32f2xx.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief ARM Cortex-M specific CPU configuration
* @{
*/
#define CPU_DEFAULT_IRQ_PRIO (1U)
#define CPU_IRQ_NUMOF (81U)
#define CPU_FLASH_BASE FLASH_BASE
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* CPU_CONF_H */
/** @} */

View File

@ -1,86 +0,0 @@
/*
* Copyright (C) 2015 Engineering-Spirit
* Copyright (C) 2016 OTA keys S.A.
*
* 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 cpu_stm32f2
* @{
*
* @file
* @brief CPU specific definitions for internal peripheral handling
*
* @author Nick v. IJzendoorn <nijzendoorn@engineering-spirit.nl>
* @author Aurelien Gonce <aurelien.gonce@altran.fr>
*/
#ifndef PERIPH_CPU_H
#define PERIPH_CPU_H
#include "periph_cpu_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Starting address of the CPU ID
*/
#define CPUID_ADDR (0x1fff7a10)
/**
* @brief Available ports on the STM32F2 family
*/
enum {
PORT_A = 0, /**< port A */
PORT_B = 1, /**< port B */
PORT_C = 2, /**< port C */
PORT_D = 3, /**< port D */
PORT_E = 4, /**< port E */
PORT_F = 5, /**< port F */
PORT_G = 6, /**< port G */
PORT_H = 7, /**< port H */
PORT_I = 8 /**< port I */
};
/**
* @brief Available number of ADC devices
*/
#define ADC_DEVS (2U)
/**
* @brief ADC channel configuration data
*/
typedef struct {
gpio_t pin; /**< pin connected to the channel */
uint8_t dev; /**< ADCx - 1 device used for the channel */
uint8_t chan; /**< CPU ADC channel connected to the pin */
} adc_conf_t;
#ifndef DOXYGEN
/**
* @brief Override the ADC resolution configuration
* @{
*/
#define HAVE_ADC_RES_T
typedef enum {
ADC_RES_6BIT = 0x03000000, /**< ADC resolution: 6 bit */
ADC_RES_8BIT = 0x02000000, /**< ADC resolution: 8 bit */
ADC_RES_10BIT = 0x01000000, /**< ADC resolution: 10 bit */
ADC_RES_12BIT = 0x00000000, /**< ADC resolution: 12 bit */
ADC_RES_14BIT = 1, /**< ADC resolution: 14 bit (not supported) */
ADC_RES_16BIT = 2 /**< ADC resolution: 16 bit (not supported)*/
} adc_res_t;
/** @} */
#endif /* ndef DOXYGEN */
#ifdef __cplusplus
}
#endif
#endif /* PERIPH_CPU_H */
/** @} */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,183 +0,0 @@
/**
******************************************************************************
* @file stm32f2xx.h
* @author MCD Application Team
* @version V2.2.0
* @date 17-March-2017
* @brief CMSIS STM32F2xx Device Peripheral Access Layer Header File.
*
* The file is the unique include file that the application programmer
* is using in the C source code, usually in main.c. This file contains:
* - Configuration section that allows to select:
* - The STM32F2xx device used in the target application
* - To use or not the peripheral’s drivers in application code(i.e.
* code will be based on direct access to peripheral’s registers
* rather than drivers API), this option is controlled by
* "#define USE_HAL_DRIVER"
*
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32f2xx
* @{
*/
#ifndef __STM32F2xx_H
#define __STM32F2xx_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/** @addtogroup Library_configuration_section
* @{
*/
/**
* @brief STM32 Family
*/
#if !defined (STM32F2)
#define STM32F2
#endif /* STM32F2 */
/* Uncomment the line below according to the target STM32 device used in your
application
*/
#if !defined (STM32F205xx) && !defined (STM32F215xx) && !defined (STM32F207xx) && !defined (STM32F217xx)
/* #define STM32F205xx */ /*!< STM32F205RG, STM32F205VG, STM32F205ZG, STM32F205RF, STM32F205VF, STM32F205ZF,
STM32F205RE, STM32F205VE, STM32F205ZE, STM32F205RC, STM32F205VC, STM32F205ZC,
STM32F205RB and STM32F205VB Devices */
/* #define STM32F215xx */ /*!< STM32F215RG, STM32F215VG, STM32F215ZG, STM32F215RE, STM32F215VE and STM32F215ZE Devices */
/* #define STM32F207xx */ /*!< STM32F207VG, STM32F207ZG, STM32F207IG, STM32F207VF, STM32F207ZF, STM32F207IF,
STM32F207VE, STM32F207ZE, STM32F207IE, STM32F207VC, STM32F207ZC and STM32F207IC Devices */
/* #define STM32F217xx */ /*!< STM32F217VG, STM32F217ZG, STM32F217IG, STM32F217VE, STM32F217ZE and STM32F217IE Devices */
#endif
/* Tip: To avoid modifying this file each time you need to switch between these
devices, you can define the device in your toolchain compiler preprocessor.
*/
#if !defined (USE_HAL_DRIVER)
/**
* @brief Comment the line below if you will not use the peripherals drivers.
In this case, these drivers will not be included and the application code will
be based on direct access to peripherals registers
*/
/*#define USE_HAL_DRIVER */
#endif /* USE_HAL_DRIVER */
/**
* @brief CMSIS Device version number V2.2.0
*/
#define __STM32F2xx_CMSIS_VERSION_MAIN (0x02U) /*!< [31:24] main version */
#define __STM32F2xx_CMSIS_VERSION_SUB1 (0x02U) /*!< [23:16] sub1 version */
#define __STM32F2xx_CMSIS_VERSION_SUB2 (0x00U) /*!< [15:8] sub2 version */
#define __STM32F2xx_CMSIS_VERSION_RC (0x00U) /*!< [7:0] release candidate */
#define __STM32F2xx_CMSIS_VERSION ((__STM32F2xx_CMSIS_VERSION_MAIN << 24)\
|(__STM32F2xx_CMSIS_VERSION_SUB1 << 16)\
|(__STM32F2xx_CMSIS_VERSION_SUB2 << 8 )\
|(__STM32F2xx_CMSIS_VERSION))
/**
* @}
*/
/** @addtogroup Device_Included
* @{
*/
#if defined(STM32F205xx)
#include "stm32f205xx.h"
#elif defined(STM32F215xx)
#include "stm32f215xx.h"
#elif defined(STM32F207xx)
#include "stm32f207xx.h"
#elif defined(STM32F217xx)
#include "stm32f217xx.h"
#else
#error "Please select first the target STM32F2xx device used in your application (in stm32f2xx.h file)"
#endif
/**
* @}
*/
/** @addtogroup Exported_macro
* @{
*/
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT))
#define READ_BIT(REG, BIT) ((REG) & (BIT))
#define CLEAR_REG(REG) ((REG) = (0x0))
#define WRITE_REG(REG, VAL) ((REG) = (VAL))
#define READ_REG(REG) ((REG))
#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))
#define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL)))
/**
* @}
*/
#if defined (USE_HAL_DRIVER)
#include "stm32f2xx_hal.h"
#endif /* USE_HAL_DRIVER */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __STM32F2xx_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -1 +0,0 @@
include $(RIOTMAKE)/periph.mk

View File

@ -1,139 +0,0 @@
/*
* Copyright (C) 2016 Engineering-Spirit
*
* 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 cpu_stm32f2
* @ingroup drivers_periph_adc
* @{
*
* @file
* @brief Low-level ADC driver implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Nick v. IJzendoorn <nijzendoorn@engineering-spirit.nl>
*
* @}
*/
#include "cpu.h"
#include "mutex.h"
#include "periph/adc.h"
#include "periph_conf.h"
/**
* @brief Maximum allowed ADC clock speed
*/
#define MAX_ADC_SPEED (12000000U)
/**
* @brief Load the ADC configuration
* @{
*/
#ifdef ADC_CONFIG
static const adc_conf_t adc_config[] = ADC_CONFIG;
#else
static const adc_conf_t adc_config[] = {};
#endif
/**
* @brief Allocate locks for all three available ADC devices
*/
static mutex_t locks[] = {
#if ADC_DEVS > 1
MUTEX_INIT,
#endif
#if ADC_DEVS > 2
MUTEX_INIT,
#endif
MUTEX_INIT
};
static inline ADC_TypeDef *dev(adc_t line)
{
return (ADC_TypeDef *)(ADC1_BASE + (adc_config[line].dev << 8));
}
static inline void prep(adc_t line)
{
mutex_lock(&locks[adc_config[line].dev]);
periph_clk_en(APB2, (RCC_APB2ENR_ADC1EN << adc_config[line].dev));
}
static inline void done(adc_t line)
{
periph_clk_dis(APB2, (RCC_APB2ENR_ADC1EN << adc_config[line].dev));
mutex_unlock(&locks[adc_config[line].dev]);
}
int adc_init(adc_t line)
{
uint32_t clk_div = 2;
/* check if the line is valid */
if (line >= ADC_NUMOF) {
return -1;
}
/* lock and power-on the device */
prep(line);
/* configure the pin */
gpio_init_analog(adc_config[line].pin);
/* set clock prescaler to get the maximal possible ADC clock value */
for (clk_div = 2; clk_div < 8; clk_div += 2) {
if ((CLOCK_CORECLOCK / clk_div) <= MAX_ADC_SPEED) {
break;
}
}
ADC->CCR = ((clk_div / 2) - 1) << 16;
/* enable the ADC module */
dev(line)->CR2 = ADC_CR2_ADON;
/* check if this channel is an internal ADC channel, if so
* enable the internal temperature and Vref */
if (adc_config[line].chan == 16 || adc_config[line].chan == 17) {
/* check if the internal channels are configured to use ADC1 */
if (dev(line) != ADC1) {
return -3;
}
ADC->CCR |= ADC_CCR_TSVREFE;
}
/* free the device again */
done(line);
return 0;
}
int32_t adc_sample(adc_t line, adc_res_t res)
{
int sample;
/* check if resolution is applicable */
if (res < 0xff) {
return -1;
}
/* lock and power on the ADC device */
prep(line);
/* set resolution and conversion channel */
dev(line)->CR1 = res;
dev(line)->SQR3 = adc_config[line].chan;
/* start conversion and wait for results */
dev(line)->CR2 |= ADC_CR2_SWSTART;
while (!(dev(line)->SR & ADC_SR_EOC)) {}
/* finally read sample and reset the STRT bit in the status register */
sample = (int)dev(line)->DR;
/* power off and unlock device again */
done(line);
return sample;
}

View File

@ -1,203 +0,0 @@
/*
* Copyright (C) 2015 Engineering-Spirit
* 2017 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.
*/
/**
* @ingroup cpu_stm32f2
* @{
*
* @file
* @brief Interrupt vector definitions
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Nick v. IJzendoorn <nijzendoorn@engineering-spirit.nl>
*
* @}
*/
#include "vectors_cortexm.h"
/* define a local dummy handler as it needs to be in the same compilation unit
* as the alias definition */
void dummy_handler(void) {
dummy_handler_default();
}
/* STM32F2 specific interrupt vectors */
WEAK_DEFAULT void isr_adc(void);
WEAK_DEFAULT void isr_can1_rx0(void);
WEAK_DEFAULT void isr_can1_rx1(void);
WEAK_DEFAULT void isr_can1_sce(void);
WEAK_DEFAULT void isr_can1_tx(void);
WEAK_DEFAULT void isr_can2_rx0(void);
WEAK_DEFAULT void isr_can2_rx1(void);
WEAK_DEFAULT void isr_can2_sce(void);
WEAK_DEFAULT void isr_can2_tx(void);
WEAK_DEFAULT void isr_cryp(void);
WEAK_DEFAULT void isr_dcmi(void);
WEAK_DEFAULT void isr_dma1_stream0(void);
WEAK_DEFAULT void isr_dma1_stream1(void);
WEAK_DEFAULT void isr_dma1_stream2(void);
WEAK_DEFAULT void isr_dma1_stream3(void);
WEAK_DEFAULT void isr_dma1_stream4(void);
WEAK_DEFAULT void isr_dma1_stream5(void);
WEAK_DEFAULT void isr_dma1_stream6(void);
WEAK_DEFAULT void isr_dma1_stream7(void);
WEAK_DEFAULT void isr_dma2_stream0(void);
WEAK_DEFAULT void isr_dma2_stream1(void);
WEAK_DEFAULT void isr_dma2_stream2(void);
WEAK_DEFAULT void isr_dma2_stream3(void);
WEAK_DEFAULT void isr_dma2_stream4(void);
WEAK_DEFAULT void isr_dma2_stream5(void);
WEAK_DEFAULT void isr_dma2_stream6(void);
WEAK_DEFAULT void isr_dma2_stream7(void);
WEAK_DEFAULT void isr_eth(void);
WEAK_DEFAULT void isr_eth_wkup(void);
WEAK_DEFAULT void isr_exti(void);
WEAK_DEFAULT void isr_flash(void);
WEAK_DEFAULT void isr_fsmc(void);
WEAK_DEFAULT void isr_hash_rng(void);
WEAK_DEFAULT void isr_i2c1_er(void);
WEAK_DEFAULT void isr_i2c1_ev(void);
WEAK_DEFAULT void isr_i2c2_er(void);
WEAK_DEFAULT void isr_i2c2_ev(void);
WEAK_DEFAULT void isr_i2c3_er(void);
WEAK_DEFAULT void isr_i2c3_ev(void);
WEAK_DEFAULT void isr_otg_fs(void);
WEAK_DEFAULT void isr_otg_fs_wkup(void);
WEAK_DEFAULT void isr_otg_hs(void);
WEAK_DEFAULT void isr_otg_hs_ep1_in(void);
WEAK_DEFAULT void isr_otg_hs_ep1_out(void);
WEAK_DEFAULT void isr_otg_hs_wkup(void);
WEAK_DEFAULT void isr_pvd(void);
WEAK_DEFAULT void isr_rcc(void);
WEAK_DEFAULT void isr_rtc_alarm(void);
WEAK_DEFAULT void isr_rtc_wkup(void);
WEAK_DEFAULT void isr_sdio(void);
WEAK_DEFAULT void isr_spi1(void);
WEAK_DEFAULT void isr_spi2(void);
WEAK_DEFAULT void isr_spi3(void);
WEAK_DEFAULT void isr_tamp_stamp(void);
WEAK_DEFAULT void isr_tim1_brk_tim9(void);
WEAK_DEFAULT void isr_tim1_cc(void);
WEAK_DEFAULT void isr_tim1_trg_com_tim11(void);
WEAK_DEFAULT void isr_tim1_up_tim10(void);
WEAK_DEFAULT void isr_tim2(void);
WEAK_DEFAULT void isr_tim3(void);
WEAK_DEFAULT void isr_tim4(void);
WEAK_DEFAULT void isr_tim5(void);
WEAK_DEFAULT void isr_tim6_dac(void);
WEAK_DEFAULT void isr_tim7(void);
WEAK_DEFAULT void isr_tim8_brk_tim12(void);
WEAK_DEFAULT void isr_tim8_cc(void);
WEAK_DEFAULT void isr_tim8_trg_com_tim14(void);
WEAK_DEFAULT void isr_tim8_up_tim13(void);
WEAK_DEFAULT void isr_uart4(void);
WEAK_DEFAULT void isr_uart5(void);
WEAK_DEFAULT void isr_usart1(void);
WEAK_DEFAULT void isr_usart2(void);
WEAK_DEFAULT void isr_usart3(void);
WEAK_DEFAULT void isr_usart6(void);
WEAK_DEFAULT void isr_wwdg(void);
/* CPU specific interrupt vector table */
ISR_VECTOR(1) const isr_t vector_cpu[CPU_IRQ_NUMOF] = {
/* shared vectors for all family members */
[ 0] = isr_wwdg, /* [ 0] Window WatchDog Interrupt */
[ 1] = isr_pvd, /* [ 1] PVD through EXTI Line detection Interrupt */
[ 2] = isr_tamp_stamp, /* [ 2] Tamper and TimeStamp interrupts through the EXTI line */
[ 3] = isr_rtc_wkup, /* [ 3] RTC Wakeup interrupt through the EXTI line */
[ 4] = isr_flash, /* [ 4] FLASH global Interrupt */
[ 5] = isr_rcc, /* [ 5] RCC global Interrupt */
[ 6] = isr_exti, /* [ 6] EXTI Line0 Interrupt */
[ 7] = isr_exti, /* [ 7] EXTI Line1 Interrupt */
[ 8] = isr_exti, /* [ 8] EXTI Line2 Interrupt */
[ 9] = isr_exti, /* [ 9] EXTI Line3 Interrupt */
[10] = isr_exti, /* [10] EXTI Line4 Interrupt */
[11] = isr_dma1_stream0, /* [11] DMA1 Stream 0 global Interrupt */
[12] = isr_dma1_stream1, /* [12] DMA1 Stream 1 global Interrupt */
[13] = isr_dma1_stream2, /* [13] DMA1 Stream 2 global Interrupt */
[14] = isr_dma1_stream3, /* [14] DMA1 Stream 3 global Interrupt */
[15] = isr_dma1_stream4, /* [15] DMA1 Stream 4 global Interrupt */
[16] = isr_dma1_stream5, /* [16] DMA1 Stream 5 global Interrupt */
[17] = isr_dma1_stream6, /* [17] DMA1 Stream 6 global Interrupt */
[18] = isr_adc, /* [18] ADC1, ADC2 and ADC3 global Interrupts */
[19] = isr_can1_tx, /* [19] CAN1 TX Interrupt */
[20] = isr_can1_rx0, /* [20] CAN1 RX0 Interrupt */
[21] = isr_can1_rx1, /* [21] CAN1 RX1 Interrupt */
[22] = isr_can1_sce, /* [22] CAN1 SCE Interrupt */
[23] = isr_exti, /* [23] External Line[9:5] Interrupts */
[24] = isr_tim1_brk_tim9, /* [24] TIM1 Break interrupt and TIM9 global interrupt */
[25] = isr_tim1_up_tim10, /* [25] TIM1 Update Interrupt and TIM10 global interrupt */
[26] = isr_tim1_trg_com_tim11, /* [26] TIM1 Trigger and Commutation Interrupt and TIM11 global interrupt */
[27] = isr_tim1_cc, /* [27] TIM1 Capture Compare Interrupt */
[28] = isr_tim2, /* [28] TIM2 global Interrupt */
[29] = isr_tim3, /* [29] TIM3 global Interrupt */
[30] = isr_tim4, /* [30] TIM4 global Interrupt */
[31] = isr_i2c1_ev, /* [31] I2C1 Event Interrupt */
[32] = isr_i2c1_er, /* [32] I2C1 Error Interrupt */
[33] = isr_i2c2_ev, /* [33] I2C2 Event Interrupt */
[34] = isr_i2c2_er, /* [34] I2C2 Error Interrupt */
[35] = isr_spi1, /* [35] SPI1 global Interrupt */
[36] = isr_spi2, /* [36] SPI2 global Interrupt */
[37] = isr_usart1, /* [37] USART1 global Interrupt */
[38] = isr_usart2, /* [38] USART2 global Interrupt */
[39] = isr_usart3, /* [39] USART3 global Interrupt */
[40] = isr_exti, /* [40] External Line[15:10] Interrupts */
[41] = isr_rtc_alarm, /* [41] RTC Alarm (A and B) through EXTI Line Interrupt */
[42] = isr_otg_fs_wkup, /* [42] USB OTG FS Wakeup through EXTI line interrupt */
[43] = isr_tim8_brk_tim12, /* [43] TIM8 Break Interrupt and TIM12 global interrupt */
[44] = isr_tim8_up_tim13, /* [44] TIM8 Update Interrupt and TIM13 global interrupt */
[45] = isr_tim8_trg_com_tim14, /* [45] TIM8 Trigger and Commutation Interrupt and TIM14 global interrupt */
[46] = isr_tim8_cc, /* [46] TIM8 Capture Compare Interrupt */
[47] = isr_dma1_stream7, /* [47] DMA1 Stream7 Interrupt */
[48] = isr_fsmc, /* [48] FSMC global Interrupt */
[49] = isr_sdio, /* [49] SDIO global Interrupt */
[50] = isr_tim5, /* [50] TIM5 global Interrupt */
[51] = isr_spi3, /* [51] SPI3 global Interrupt */
[52] = isr_uart4, /* [52] UART4 global Interrupt */
[53] = isr_uart5, /* [53] UART5 global Interrupt */
[54] = isr_tim6_dac, /* [54] TIM6 global and DAC1&2 underrun error interrupts */
[55] = isr_tim7, /* [55] TIM7 global interrupt */
[56] = isr_dma2_stream0, /* [56] DMA2 Stream 0 global Interrupt */
[57] = isr_dma2_stream1, /* [57] DMA2 Stream 1 global Interrupt */
[58] = isr_dma2_stream2, /* [58] DMA2 Stream 2 global Interrupt */
[59] = isr_dma2_stream3, /* [59] DMA2 Stream 3 global Interrupt */
[60] = isr_dma2_stream4, /* [60] DMA2 Stream 4 global Interrupt */
[63] = isr_can2_tx, /* [63] CAN2 TX Interrupt */
[64] = isr_can2_rx0, /* [64] CAN2 RX0 Interrupt */
[65] = isr_can2_rx1, /* [65] CAN2 RX1 Interrupt */
[66] = isr_can2_sce, /* [66] CAN2 SCE Interrupt */
[67] = isr_otg_fs, /* [67] USB OTG FS global Interrupt */
[68] = isr_dma2_stream5, /* [68] DMA2 Stream 5 global interrupt */
[69] = isr_dma2_stream6, /* [69] DMA2 Stream 6 global interrupt */
[70] = isr_dma2_stream7, /* [70] DMA2 Stream 7 global interrupt */
[71] = isr_usart6, /* [71] USART6 global interrupt */
[72] = isr_i2c3_ev, /* [72] I2C3 event interrupt */
[73] = isr_i2c3_er, /* [73] I2C3 error interrupt */
[74] = isr_otg_hs_ep1_out, /* [74] USB OTG HS End Point 1 Out global interrupt */
[75] = isr_otg_hs_ep1_in, /* [75] USB OTG HS End Point 1 In global interrupt */
[76] = isr_otg_hs_wkup, /* [76] USB OTG HS Wakeup through EXTI interrupt */
[77] = isr_otg_hs, /* [77] USB OTG HS global interrupt */
#if defined(CPU_LINE_STM32F207xx)
[61] = isr_eth, /* [61] Ethernet global Interrupt */
[62] = isr_eth_wkup, /* [62] Ethernet Wakeup through EXTI line Interrupt */
[78] = isr_dcmi, /* [78] DCMI global interrupt */
[80] = isr_hash_rng, /* [80] Hash and RNG global interrupt */
#elif defined(CPU_LINE_STM32F215xx)
[79] = isr_cryp, /* [79] CRYP crypto global interrupt */
[80] = isr_hash_rng, /* [80] Hash and RNG global interrupt */
#elif defined(CPU_LINE_STM32F217xx)
[61] = isr_eth, /* [61] Ethernet global Interrupt */
[62] = isr_eth_wkup, /* [62] Ethernet Wakeup through EXTI line Interrupt */
[78] = isr_dcmi, /* [78] DCMI global interrupt */
[79] = isr_cryp, /* [79] CRYP crypto global interrupt */
[80] = isr_hash_rng, /* [80] Hash and Rng global interrupt */
#endif
};

View File

@ -1,10 +0,0 @@
# define the module that is build
MODULE = cpu
# add a list of subdirectories, that should also be build
DIRS = periph $(RIOTCPU)/cortexm_common $(RIOTCPU)/stm32_common
# (file triggers compiler bug. see #5775)
SRC_NOLTO += vectors.c
include $(RIOTBASE)/Makefile.base

View File

@ -1 +0,0 @@
include $(RIOTCPU)/stm32_common/Makefile.dep

View File

@ -1,13 +0,0 @@
CPU_ARCH = cortex-m4f
CPU_FAM = stm32f3
FEATURES_PROVIDED += periph_flashpage
FEATURES_PROVIDED += periph_flashpage_raw
# only some stm32f3 have an MPU
STM32F3_WITH_MPU += stm32f303re stm32f303vc stm32f303ze
ifneq (, $(filter $(CPU_MODEL), $(STM32F3_WITH_MPU)))
FEATURES_PROVIDED += cortexm_mpu
endif
-include $(RIOTCPU)/stm32_common/Makefile.features

Some files were not shown because too many files have changed in this diff Show More