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:
parent
facb626b02
commit
7d4b29530a
@ -1,5 +0,0 @@
|
||||
MODULE = stm32_common
|
||||
|
||||
DIRS = periph
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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();
|
||||
}
|
||||
2
cpu/stm32_common/dist/.gitignore
vendored
2
cpu/stm32_common/dist/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
clk_conf
|
||||
spi_divtable
|
||||
12
cpu/stm32_common/dist/clk_conf/Makefile
vendored
12
cpu/stm32_common/dist/clk_conf/Makefile
vendored
@ -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)
|
||||
502
cpu/stm32_common/dist/clk_conf/clk_conf.c
vendored
502
cpu/stm32_common/dist/clk_conf/clk_conf.c
vendored
@ -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;
|
||||
}
|
||||
602
cpu/stm32_common/dist/clk_conf/clk_conf.h
vendored
602
cpu/stm32_common/dist/clk_conf/clk_conf.h
vendored
@ -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 */
|
||||
12
cpu/stm32_common/dist/spi_divtable/Makefile
vendored
12
cpu/stm32_common/dist/spi_divtable/Makefile
vendored
@ -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)
|
||||
105
cpu/stm32_common/dist/spi_divtable/spi_divtable.c
vendored
105
cpu/stm32_common/dist/spi_divtable/spi_divtable.c
vendored
@ -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;
|
||||
}
|
||||
@ -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.
|
||||
*/
|
||||
@ -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 */
|
||||
@ -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 */
|
||||
@ -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 */
|
||||
/** @} */
|
||||
@ -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 */
|
||||
/** @} */
|
||||
@ -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 */
|
||||
/** @} */
|
||||
@ -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 */
|
||||
/** @} */
|
||||
@ -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
|
||||
@ -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
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
@ -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 */
|
||||
@ -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, ®, (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 */
|
||||
@ -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 */
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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 */
|
||||
@ -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 */
|
||||
@ -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 */
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
@ -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
@ -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
|
||||
@ -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
|
||||
@ -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) */
|
||||
@ -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);
|
||||
}
|
||||
@ -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) */
|
||||
@ -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
|
||||
@ -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
|
||||
@ -1 +0,0 @@
|
||||
include $(RIOTCPU)/stm32_common/Makefile.dep
|
||||
@ -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
|
||||
@ -1,2 +0,0 @@
|
||||
include $(RIOTCPU)/stm32_common/Makefile.include
|
||||
include $(RIOTMAKE)/arch/cortexm.inc.mk
|
||||
@ -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 */
|
||||
/** @} */
|
||||
@ -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 */
|
||||
/** @} */
|
||||
5368
cpu/stm32f0/include/vendor/stm32f030x4.h
vendored
5368
cpu/stm32f0/include/vendor/stm32f030x4.h
vendored
File diff suppressed because it is too large
Load Diff
5395
cpu/stm32f0/include/vendor/stm32f030x8.h
vendored
5395
cpu/stm32f0/include/vendor/stm32f030x8.h
vendored
File diff suppressed because it is too large
Load Diff
5852
cpu/stm32f0/include/vendor/stm32f030xc.h
vendored
5852
cpu/stm32f0/include/vendor/stm32f030xc.h
vendored
File diff suppressed because it is too large
Load Diff
5646
cpu/stm32f0/include/vendor/stm32f031x6.h
vendored
5646
cpu/stm32f0/include/vendor/stm32f031x6.h
vendored
File diff suppressed because it is too large
Load Diff
5303
cpu/stm32f0/include/vendor/stm32f042x6.h
vendored
5303
cpu/stm32f0/include/vendor/stm32f042x6.h
vendored
File diff suppressed because it is too large
Load Diff
3791
cpu/stm32f0/include/vendor/stm32f051x8.h
vendored
3791
cpu/stm32f0/include/vendor/stm32f051x8.h
vendored
File diff suppressed because it is too large
Load Diff
5759
cpu/stm32f0/include/vendor/stm32f070xb.h
vendored
5759
cpu/stm32f0/include/vendor/stm32f070xb.h
vendored
File diff suppressed because it is too large
Load Diff
11247
cpu/stm32f0/include/vendor/stm32f072xb.h
vendored
11247
cpu/stm32f0/include/vendor/stm32f072xb.h
vendored
File diff suppressed because it is too large
Load Diff
11864
cpu/stm32f0/include/vendor/stm32f091xc.h
vendored
11864
cpu/stm32f0/include/vendor/stm32f091xc.h
vendored
File diff suppressed because it is too large
Load Diff
218
cpu/stm32f0/include/vendor/stm32f0xx.h
vendored
218
cpu/stm32f0/include/vendor/stm32f0xx.h
vendored
@ -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 peripherals drivers in application code(i.e.
|
||||
* code will be based on direct access to peripherals registers
|
||||
* rather than drivers API), this option is controlled by
|
||||
* "#define USE_HAL_DRIVER"
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© 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****/
|
||||
@ -1 +0,0 @@
|
||||
include $(RIOTMAKE)/periph.mk
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
@ -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
|
||||
};
|
||||
@ -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
|
||||
@ -1 +0,0 @@
|
||||
include $(RIOTCPU)/stm32_common/Makefile.dep
|
||||
@ -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
|
||||
@ -1,2 +0,0 @@
|
||||
include $(RIOTCPU)/stm32_common/Makefile.include
|
||||
include $(RIOTMAKE)/arch/cortexm.inc.mk
|
||||
@ -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 */
|
||||
/** @} */
|
||||
@ -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 */
|
||||
/** @} */
|
||||
6044
cpu/stm32f1/include/vendor/stm32f103xb.h
vendored
6044
cpu/stm32f1/include/vendor/stm32f103xb.h
vendored
File diff suppressed because it is too large
Load Diff
6846
cpu/stm32f1/include/vendor/stm32f103xe.h
vendored
6846
cpu/stm32f1/include/vendor/stm32f103xe.h
vendored
File diff suppressed because it is too large
Load Diff
212
cpu/stm32f1/include/vendor/stm32f1xx.h
vendored
212
cpu/stm32f1/include/vendor/stm32f1xx.h
vendored
@ -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 peripherals drivers in application code(i.e.
|
||||
* code will be based on direct access to peripherals registers
|
||||
* rather than drivers API), this option is controlled by
|
||||
* "#define USE_HAL_DRIVER"
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© 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****/
|
||||
@ -1 +0,0 @@
|
||||
include $(RIOTMAKE)/periph.mk
|
||||
@ -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;
|
||||
}
|
||||
@ -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 */
|
||||
@ -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();
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
@ -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
|
||||
@ -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
|
||||
};
|
||||
@ -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
|
||||
@ -1 +0,0 @@
|
||||
include $(RIOTCPU)/stm32_common/Makefile.dep
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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 */
|
||||
/** @} */
|
||||
@ -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 */
|
||||
/** @} */
|
||||
7661
cpu/stm32f2/include/vendor/stm32f205xx.h
vendored
7661
cpu/stm32f2/include/vendor/stm32f205xx.h
vendored
File diff suppressed because it is too large
Load Diff
14997
cpu/stm32f2/include/vendor/stm32f207xx.h
vendored
14997
cpu/stm32f2/include/vendor/stm32f207xx.h
vendored
File diff suppressed because it is too large
Load Diff
7819
cpu/stm32f2/include/vendor/stm32f215xx.h
vendored
7819
cpu/stm32f2/include/vendor/stm32f215xx.h
vendored
File diff suppressed because it is too large
Load Diff
8471
cpu/stm32f2/include/vendor/stm32f217xx.h
vendored
8471
cpu/stm32f2/include/vendor/stm32f217xx.h
vendored
File diff suppressed because it is too large
Load Diff
183
cpu/stm32f2/include/vendor/stm32f2xx.h
vendored
183
cpu/stm32f2/include/vendor/stm32f2xx.h
vendored
@ -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 peripherals drivers in application code(i.e.
|
||||
* code will be based on direct access to peripherals registers
|
||||
* rather than drivers API), this option is controlled by
|
||||
* "#define USE_HAL_DRIVER"
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© 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****/
|
||||
@ -1 +0,0 @@
|
||||
include $(RIOTMAKE)/periph.mk
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
};
|
||||
@ -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
|
||||
@ -1 +0,0 @@
|
||||
include $(RIOTCPU)/stm32_common/Makefile.dep
|
||||
@ -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
Loading…
x
Reference in New Issue
Block a user