mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
stm32l1: initial port for the nucleo-l1 board and stm32l1 cpu
This commit is contained in:
parent
d8d3e7e4e5
commit
07d76d7127
3
boards/nucleo-l1/Makefile
Normal file
3
boards/nucleo-l1/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE =$(BOARD)_base
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
2
boards/nucleo-l1/Makefile.features
Normal file
2
boards/nucleo-l1/Makefile.features
Normal file
@ -0,0 +1,2 @@
|
||||
FEATURES_PROVIDED += periph_gpio periph_uart periph_spi periph_i2c periph_cpuid
|
||||
FEATURES_PROVIDED += cpp
|
56
boards/nucleo-l1/Makefile.include
Normal file
56
boards/nucleo-l1/Makefile.include
Normal file
@ -0,0 +1,56 @@
|
||||
## the cpu to build for
|
||||
export CPU = stm32l1
|
||||
export CPU_MODEL = stm32l152ret6
|
||||
|
||||
#define the default port depending on the host OS
|
||||
OS := $(shell uname)
|
||||
ifeq ($(OS),Linux)
|
||||
PORT ?= /dev/ttyACM0
|
||||
else ifeq ($(OS),Darwin)
|
||||
PORT ?= $(shell ls -1 /dev/tty.SLAB_USBtoUART* | head -n 1)
|
||||
else
|
||||
$(info CAUTION: No flash tool for your host system found!)
|
||||
# TODO: add support for windows as host platform
|
||||
endif
|
||||
export PORT
|
||||
|
||||
# define tools used for building the project
|
||||
export PREFIX = arm-none-eabi-
|
||||
export CC = $(PREFIX)gcc
|
||||
export CXX = $(PREFIX)g++
|
||||
export AR = $(PREFIX)ar
|
||||
export AS = $(PREFIX)as
|
||||
export LINK = $(PREFIX)gcc
|
||||
export SIZE = $(PREFIX)size
|
||||
export OBJCOPY = $(PREFIX)objcopy
|
||||
export TERMPROG = $(RIOTBASE)/dist/tools/pyterm/pyterm
|
||||
export FLASHER = $(RIOTBOARD)/$(BOARD)/dist/flash.sh
|
||||
export DEBUGGER = $(RIOTBOARD)/$(BOARD)/dist/debug.sh
|
||||
export DEBUGSERVER = $(RIOTBOARD)/$(BOARD)/dist/debug-server.sh
|
||||
export RESET = $(RIOTBOARD)/$(BOARD)/dist/reset.sh
|
||||
|
||||
# unwanted (CXXUWFLAGS) and extra (CXXEXFLAGS) flags for c++
|
||||
export CXXUWFLAGS +=
|
||||
export CXXEXFLAGS +=
|
||||
|
||||
# define build specific options
|
||||
export CPU_USAGE = -mcpu=cortex-m3
|
||||
export FPU_USAGE =
|
||||
export CFLAGS += -ggdb -g3 -std=gnu99 -Os -Wall -Wstrict-prototypes $(CPU_USAGE) $(FPU_USAGE) -mlittle-endian -mthumb -mthumb-interwork -nostartfiles
|
||||
export CFLAGS += -ffunction-sections -fdata-sections -fno-builtin
|
||||
export ASFLAGS += -ggdb -g3 $(CPU_USAGE) $(FPU_USAGE) -mlittle-endian
|
||||
export LINKFLAGS += -ggdb -g3 -std=gnu99 $(CPU_USAGE) $(FPU_USAGE) -mlittle-endian -static -lgcc -mthumb -mthumb-interwork -nostartfiles
|
||||
# $(LINKERSCRIPT) is specified in cpu/Makefile.include
|
||||
export LINKFLAGS += -T$(LINKERSCRIPT)
|
||||
export OFLAGS = -O binary
|
||||
export FFLAGS = $(HEXFILE)
|
||||
export DEBUGGER_FLAGS = $(RIOTBOARD)/$(BOARD)/dist/gdb.conf $(ELFFILE)
|
||||
export TERMFLAGS += -p "$(PORT)"
|
||||
|
||||
# use the nano-specs of the NewLib when available
|
||||
ifeq ($(shell $(LINK) -specs=nano.specs -E - 2>/dev/null >/dev/null </dev/null ; echo $$?),0)
|
||||
export LINKFLAGS += -specs=nano.specs -lc -lnosys
|
||||
endif
|
||||
|
||||
# export board specific includes to the global includes-listing
|
||||
export INCLUDES += -I$(RIOTBOARD)/$(BOARD)/include/
|
60
boards/nucleo-l1/board.c
Normal file
60
boards/nucleo-l1/board.c
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 board_nucleo-l1
|
||||
* @{
|
||||
*
|
||||
* @file board.c
|
||||
* @brief Board specific implementations for the nucleo-l1 board
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "board.h"
|
||||
#include "cpu.h"
|
||||
|
||||
static void leds_init(void);
|
||||
|
||||
void board_init(void)
|
||||
{
|
||||
/* initialize the CPU */
|
||||
cpu_init();
|
||||
|
||||
/* initialize the boards LEDs */
|
||||
leds_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the boards on-board LEDs
|
||||
*
|
||||
* The LED initialization is hard-coded in this function. As the LED is soldered
|
||||
* onto the board it is fixed to its CPU pins.
|
||||
*
|
||||
* The green LED is connected to pin PA5
|
||||
*/
|
||||
static void leds_init(void)
|
||||
{
|
||||
/* enable clock for port GPIOE */
|
||||
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
|
||||
|
||||
/* set output speed to 50MHz */
|
||||
LED_GREEN_PORT->OSPEEDR |= 0x00000c00;
|
||||
/* set output type to push-pull */
|
||||
LED_GREEN_PORT->OTYPER &= ~(0x00000020);
|
||||
/* configure pins as general outputs */
|
||||
LED_GREEN_PORT->MODER &= ~(0x00000c00);
|
||||
LED_GREEN_PORT->MODER |= 0x00000400;
|
||||
/* disable pull resistors */
|
||||
LED_GREEN_PORT->PUPDR &= ~(0x00000c00);
|
||||
|
||||
/* turn all LEDs off */
|
||||
LED_GREEN_PORT->BRR = 0x00c0;
|
||||
}
|
10
boards/nucleo-l1/dist/debug-server.sh
vendored
Executable file
10
boards/nucleo-l1/dist/debug-server.sh
vendored
Executable file
@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "##"
|
||||
echo "## Starting debug server"
|
||||
echo "##"
|
||||
|
||||
openocd -f "${RIOTBOARD}/${BOARD}/dist/openocd.cfg" \
|
||||
-c "init" \
|
||||
-c "targets" \
|
||||
-c "reset halt"
|
11
boards/nucleo-l1/dist/debug.sh
vendored
Executable file
11
boards/nucleo-l1/dist/debug.sh
vendored
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ ! -f "$2" ]; then
|
||||
echo "ELF-file $2 does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "##"
|
||||
echo "## Debugging $2"
|
||||
echo "##"
|
||||
arm-none-eabi-gdb -tui -command="$1" $2
|
13
boards/nucleo-l1/dist/flash.sh
vendored
Executable file
13
boards/nucleo-l1/dist/flash.sh
vendored
Executable file
@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "##"
|
||||
echo "## Flashing $1"
|
||||
echo "##"
|
||||
|
||||
openocd -f "${RIOTBOARD}/${BOARD}/dist/openocd.cfg" \
|
||||
-c "init" \
|
||||
-c "targets" \
|
||||
-c "reset halt" \
|
||||
-c "program $1 0x8000000 verify" \
|
||||
-c "reset run"\
|
||||
-c "shutdown"
|
1
boards/nucleo-l1/dist/gdb.conf
vendored
Executable file
1
boards/nucleo-l1/dist/gdb.conf
vendored
Executable file
@ -0,0 +1 @@
|
||||
tar extended-remote :3333
|
6
boards/nucleo-l1/dist/openocd.cfg
vendored
Normal file
6
boards/nucleo-l1/dist/openocd.cfg
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
# stml1 Target
|
||||
source [find interface/stlink-v2-1.cfg]
|
||||
|
||||
transport select hla_swd
|
||||
|
||||
source [find target/stm32l.cfg]
|
10
boards/nucleo-l1/dist/reset.sh
vendored
Executable file
10
boards/nucleo-l1/dist/reset.sh
vendored
Executable file
@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "##"
|
||||
echo "## Resetting $1"
|
||||
echo "##"
|
||||
|
||||
openocd -f "${RIOTBOARD}/${BOARD}/dist/openocd.cfg" \
|
||||
-c "init" \
|
||||
-c "reset run"\
|
||||
-c "shutdown"
|
93
boards/nucleo-l1/include/board.h
Normal file
93
boards/nucleo-l1/include/board.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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 board_nucleo-l1 nucleo-l1
|
||||
* @ingroup boards
|
||||
* @brief Board specific files for the nucleo-l1 board.
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Board specific definitions for the nucleo-l1 board.
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef BOARD_H_
|
||||
#define BOARD_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "periph_conf.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name Define the nominal CPU core clock in this board
|
||||
*/
|
||||
#define F_CPU CLOCK_CORECLOCK
|
||||
|
||||
/**
|
||||
* @name Define the UART to be used as stdio and its baudrate
|
||||
* @{
|
||||
*/
|
||||
#define STDIO UART_0
|
||||
#define STDIO_BAUDRATE (115200U)
|
||||
#define STDIO_RX_BUFSIZE (64U)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Assign the hardware timer
|
||||
*/
|
||||
#define HW_TIMER TIMER_0
|
||||
|
||||
/**
|
||||
* @name LED pin definitions
|
||||
* @{
|
||||
*/
|
||||
#define LED_GREEN_PORT (GPIOA)
|
||||
#define LED_GREEN_PIN (5)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Macros for controlling the on-board LEDs.
|
||||
* @{
|
||||
*/
|
||||
#define LED_RED_ON
|
||||
#define LED_RED_OFF
|
||||
#define LED_RED_TOGGLE
|
||||
|
||||
#define LED_GREEN_ON (LED_GREEN_PORT->ODR &= ~(1<<LED_GREEN_PIN))
|
||||
#define LED_GREEN_OFF (LED_GREEN_PORT->ODR |= (1<<LED_GREEN_PIN))
|
||||
#define LED_GREEN_TOGGLE (LED_GREEN_PORT->ODR ^= (1<<LED_GREEN_PIN))
|
||||
|
||||
#define LED_ORANGE_ON
|
||||
#define LED_ORANGE_OFF
|
||||
#define LED_ORANGE_TOGGLE
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Define the type for the radio packet length for the transceiver
|
||||
*/
|
||||
typedef uint8_t radio_packet_length_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize board specific hardware, including clock, LEDs and std-IO
|
||||
*/
|
||||
void board_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BOARD_H_ */
|
||||
/** @} */
|
||||
/** @} */
|
292
boards/nucleo-l1/include/periph_conf.h
Normal file
292
boards/nucleo-l1/include/periph_conf.h
Normal file
@ -0,0 +1,292 @@
|
||||
/*
|
||||
* 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 board_nucleo-l1
|
||||
* @{
|
||||
*
|
||||
* @file periph_conf.h
|
||||
* @brief Peripheral MCU configuration for the nucleo-l1 board
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef __PERIPH_CONF_H
|
||||
#define __PERIPH_CONF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name Clock system configuration
|
||||
* @{
|
||||
**/
|
||||
#define CLOCK_HSI (16000000U) /* frequency of external oscillator */
|
||||
#define CLOCK_CORECLOCK (32000000U) /* targeted core clock frequency */
|
||||
/* configuration of PLL prescaler and multiply values */
|
||||
/* CORECLOCK := HSI / PLL_HSI_DIV * PLL_HSI_MUL */
|
||||
#define CLOCK_PLL_HSE_DIV RCC_CFGR_PLLDIV2
|
||||
#define CLOCK_PLL_HSE_MUL RCC_CFGR_PLLMUL4
|
||||
/* configuration of peripheral bus clock prescalers */
|
||||
#define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 /* AHB clock -> 32MHz */
|
||||
#define CLOCK_APB2_DIV RCC_CFGR_PPRE2_DIV1 /* APB2 clock -> 32MHz */
|
||||
#define CLOCK_APB1_DIV RCC_CFGR_PPRE1_DIV1 /* APB1 clock -> 32MHz */
|
||||
/* configuration of flash access cycles */
|
||||
#define CLOCK_FLASH_LATENCY FLASH_ACR_LATENCY
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Timer configuration
|
||||
* @{
|
||||
*/
|
||||
#define TIMER_NUMOF (2U)
|
||||
#define TIMER_0_EN 1
|
||||
#define TIMER_1_EN 1
|
||||
|
||||
/* Timer 0 configuration */
|
||||
#define TIMER_0_DEV_0 TIM2
|
||||
#define TIMER_0_DEV_1 TIM3
|
||||
#define TIMER_0_CHANNELS 4
|
||||
#define TIMER_0_PRESCALER (32U)
|
||||
#define TIMER_0_MAX_VALUE (0xffff)
|
||||
#define TIMER_0_CLKEN() (RCC->APB1ENR |= (RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN))
|
||||
#define TIMER_0_ISR_0 isr_tim2
|
||||
#define TIMER_0_ISR_1 isr_tim3
|
||||
#define TIMER_0_IRQ_CHAN_0 TIM2_IRQn
|
||||
#define TIMER_0_IRQ_CHAN_1 TIM3_IRQn
|
||||
#define TIMER_0_IRQ_PRIO 1
|
||||
#define TIMER_0_TRIG_SEL TIM_SMCR_TS_0
|
||||
|
||||
/* Timer 1 configuration */
|
||||
#define TIMER_1_DEV_0 TIM4
|
||||
#define TIMER_1_DEV_1 TIM5
|
||||
#define TIMER_1_CHANNELS 4
|
||||
#define TIMER_1_PRESCALER (32U)
|
||||
#define TIMER_1_MAX_VALUE (0xffff)
|
||||
#define TIMER_1_CLKEN() (RCC->APB1ENR |= (RCC_APB1ENR_TIM4EN | RCC_APB1ENR_TIM5EN))
|
||||
#define TIMER_1_ISR_0 isr_tim4
|
||||
#define TIMER_1_ISR_1 isr_tim5
|
||||
#define TIMER_1_IRQ_CHAN_0 TIM4_IRQn
|
||||
#define TIMER_1_IRQ_CHAN_1 TIM5_IRQn
|
||||
#define TIMER_1_IRQ_PRIO 1
|
||||
#define TIMER_1_TRIG_SEL TIM_SMCR_TS_1
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief UART configuration
|
||||
*/
|
||||
#define UART_NUMOF (1U)
|
||||
#define UART_0_EN 1
|
||||
#define UART_IRQ_PRIO 1
|
||||
|
||||
/* UART 0 device configuration */
|
||||
#define UART_0_DEV USART2
|
||||
#define UART_0_CLKEN() (RCC->APB1ENR |= RCC_APB1ENR_USART2EN)
|
||||
#define UART_0_CLK (CLOCK_CORECLOCK) /* UART clock runs with 32MHz (F_CPU / 1) */
|
||||
#define UART_0_IRQ USART2_IRQn
|
||||
#define UART_0_ISR isr_usart2
|
||||
#define UART_0_BUS_FREQ 32000000
|
||||
/* UART 0 pin configuration */
|
||||
#define UART_0_PORT GPIOA
|
||||
#define UART_0_PORT_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOAEN)
|
||||
#define UART_0_RX_PIN 3
|
||||
#define UART_0_TX_PIN 2
|
||||
#define UART_0_AF 7
|
||||
|
||||
/**
|
||||
* @brief GPIO configuration
|
||||
*/
|
||||
#define GPIO_NUMOF 16
|
||||
#define GPIO_0_EN 1
|
||||
#define GPIO_1_EN 1
|
||||
#define GPIO_2_EN 1
|
||||
#define GPIO_3_EN 1
|
||||
#define GPIO_4_EN 1
|
||||
#define GPIO_5_EN 1
|
||||
#define GPIO_6_EN 1
|
||||
#define GPIO_7_EN 1
|
||||
#define GPIO_8_EN 1
|
||||
#define GPIO_9_EN 1
|
||||
#define GPIO_10_EN 1
|
||||
#define GPIO_11_EN 1
|
||||
#define GPIO_12_EN 1
|
||||
#define GPIO_13_EN 1
|
||||
#define GPIO_14_EN 1
|
||||
#define GPIO_15_EN 1
|
||||
#define GPIO_IRQ_PRIO 1
|
||||
|
||||
/* IRQ config */
|
||||
#define GPIO_IRQ_0 GPIO_13
|
||||
#define GPIO_IRQ_1 GPIO_14
|
||||
#define GPIO_IRQ_2 GPIO_7
|
||||
#define GPIO_IRQ_3 GPIO_0
|
||||
#define GPIO_IRQ_4 GPIO_5
|
||||
#define GPIO_IRQ_5 GPIO_12
|
||||
#define GPIO_IRQ_6 GPIO_11
|
||||
#define GPIO_IRQ_7 GPIO_1
|
||||
#define GPIO_IRQ_8 GPIO_3
|
||||
#define GPIO_IRQ_9 GPIO_2
|
||||
#define GPIO_IRQ_10 GPIO_4
|
||||
#define GPIO_IRQ_11 GPIO_6
|
||||
#define GPIO_IRQ_12 GPIO_15
|
||||
#define GPIO_IRQ_13 GPIO_8
|
||||
#define GPIO_IRQ_14 GPIO_9
|
||||
#define GPIO_IRQ_15 GPIO_10
|
||||
|
||||
/* GPIO channel 0 config */
|
||||
#define GPIO_0_PORT GPIOA /* Used for user button 1 */
|
||||
#define GPIO_0_PIN 3
|
||||
#define GPIO_0_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOAEN)
|
||||
#define GPIO_0_EXTI_CFG() (SYSCFG->EXTICR[0] |= SYSCFG_EXTICR1_EXTI3_PA)
|
||||
#define GPIO_0_IRQ EXTI3_IRQn
|
||||
/* GPIO channel 1 config */
|
||||
#define GPIO_1_PORT GPIOC
|
||||
#define GPIO_1_PIN 7
|
||||
#define GPIO_1_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOCEN)
|
||||
#define GPIO_1_EXTI_CFG() (SYSCFG->EXTICR[1] |= SYSCFG_EXTICR2_EXTI7_PC)
|
||||
#define GPIO_1_IRQ EXTI9_5_IRQn
|
||||
/* GPIO channel 2 config */
|
||||
#define GPIO_2_PORT GPIOA
|
||||
#define GPIO_2_PIN 9
|
||||
#define GPIO_2_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOAEN)
|
||||
#define GPIO_2_EXTI_CFG() (SYSCFG->EXTICR[2] |= SYSCFG_EXTICR3_EXTI9_PA)
|
||||
#define GPIO_2_IRQ EXTI9_5_IRQn
|
||||
/* GPIO channel 3 config */
|
||||
#define GPIO_3_PORT GPIOA
|
||||
#define GPIO_3_PIN 8
|
||||
#define GPIO_3_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOAEN)
|
||||
#define GPIO_3_EXTI_CFG() (SYSCFG->EXTICR[2] |= SYSCFG_EXTICR3_EXTI8_PA)
|
||||
#define GPIO_3_IRQ EXTI9_5_IRQn
|
||||
/* GPIO channel 4 config */
|
||||
#define GPIO_4_PORT GPIOB
|
||||
#define GPIO_4_PIN 10
|
||||
#define GPIO_4_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOBEN)
|
||||
#define GPIO_4_EXTI_CFG() (SYSCFG->EXTICR[2] |= SYSCFG_EXTICR3_EXTI10_PB)
|
||||
#define GPIO_4_IRQ EXTI15_10_IRQn
|
||||
/* GPIO channel 5 config */
|
||||
#define GPIO_5_PORT GPIOB
|
||||
#define GPIO_5_PIN 4
|
||||
#define GPIO_5_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOBEN)
|
||||
#define GPIO_5_EXTI_CFG() (SYSCFG->EXTICR[1] |= SYSCFG_EXTICR2_EXTI4_PB)
|
||||
#define GPIO_5_IRQ EXTI4_IRQn
|
||||
/* GPIO channel 6 config */
|
||||
#define GPIO_6_PORT GPIOC
|
||||
#define GPIO_6_PIN 11
|
||||
#define GPIO_6_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOCEN)
|
||||
#define GPIO_6_EXTI_CFG() (SYSCFG->EXTICR[2] |= SYSCFG_EXTICR3_EXTI11_PC)
|
||||
#define GPIO_6_IRQ EXTI15_10_IRQn
|
||||
/* GPIO channel 7 config */
|
||||
#define GPIO_7_PORT GPIOC
|
||||
#define GPIO_7_PIN 2
|
||||
#define GPIO_7_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOCEN)
|
||||
#define GPIO_7_EXTI_CFG() (SYSCFG->EXTICR[0] |= SYSCFG_EXTICR1_EXTI2_PC)
|
||||
#define GPIO_7_IRQ EXTI2_IRQn
|
||||
/* GPIO channel 8 config */
|
||||
#define GPIO_8_PORT GPIOA
|
||||
#define GPIO_8_PIN 13
|
||||
#define GPIO_8_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOAEN)
|
||||
#define GPIO_8_EXTI_CFG() (SYSCFG->EXTICR[3] |= SYSCFG_EXTICR4_EXTI13_PA)
|
||||
#define GPIO_8_IRQ EXTI15_10_IRQn
|
||||
/* GPIO channel 9 config */
|
||||
#define GPIO_9_PORT GPIOA
|
||||
#define GPIO_9_PIN 14
|
||||
#define GPIO_9_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOAEN)
|
||||
#define GPIO_9_EXTI_CFG() (SYSCFG->EXTICR[3] |= SYSCFG_EXTICR4_EXTI14_PA)
|
||||
#define GPIO_9_IRQ EXTI15_10_IRQn
|
||||
/* GPIO channel 10 config */
|
||||
#define GPIO_10_PORT GPIOA
|
||||
#define GPIO_10_PIN 15
|
||||
#define GPIO_10_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOAEN)
|
||||
#define GPIO_10_EXTI_CFG() (SYSCFG->EXTICR[3] |= SYSCFG_EXTICR4_EXTI15_PA)
|
||||
#define GPIO_10_IRQ EXTI15_10_IRQn
|
||||
/* GPIO channel 11 config */
|
||||
#define GPIO_11_PORT GPIOB /* SPI CS Pin */
|
||||
#define GPIO_11_PIN 6
|
||||
#define GPIO_11_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOBEN)
|
||||
#define GPIO_11_EXTI_CFG() (SYSCFG->EXTICR[1] |= SYSCFG_EXTICR2_EXTI6_PB)
|
||||
#define GPIO_11_IRQ EXTI9_5_IRQn
|
||||
/* GPIO channel 12 config */
|
||||
#define GPIO_12_PORT GPIOC
|
||||
#define GPIO_12_PIN 5
|
||||
#define GPIO_12_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOCEN)
|
||||
#define GPIO_12_EXTI_CFG() (SYSCFG->EXTICR[1] |= SYSCFG_EXTICR2_EXTI5_PC)
|
||||
#define GPIO_12_IRQ EXTI9_5_IRQn
|
||||
/* GPIO channel 13 config */
|
||||
#define GPIO_13_PORT GPIOA
|
||||
#define GPIO_13_PIN 0
|
||||
#define GPIO_13_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOAEN)
|
||||
#define GPIO_13_EXTI_CFG() (SYSCFG->EXTICR[0] |= SYSCFG_EXTICR1_EXTI0_PA)
|
||||
#define GPIO_13_IRQ EXTI0_IRQn
|
||||
/* GPIO channel 14 config */
|
||||
#define GPIO_14_PORT GPIOA
|
||||
#define GPIO_14_PIN 1
|
||||
#define GPIO_14_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOAEN)
|
||||
#define GPIO_14_EXTI_CFG() (SYSCFG->EXTICR[0] |= SYSCFG_EXTICR1_EXTI1_PA)
|
||||
#define GPIO_14_IRQ EXTI1_IRQn
|
||||
/* GPIO channel 15 config */
|
||||
#define GPIO_15_PORT GPIOC
|
||||
#define GPIO_15_PIN 12
|
||||
#define GPIO_15_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOCEN)
|
||||
#define GPIO_15_EXTI_CFG() (SYSCFG->EXTICR[3] |= SYSCFG_EXTICR4_EXTI12_PC)
|
||||
#define GPIO_15_IRQ EXTI15_10_IRQn
|
||||
|
||||
/**
|
||||
* @brief SPI configuration
|
||||
* @{
|
||||
*/
|
||||
#define SPI_NUMOF (1U)
|
||||
#define SPI_0_EN 1
|
||||
|
||||
/* SPI 0 device configuration */
|
||||
#define SPI_0_DEV SPI1
|
||||
#define SPI_0_CLKEN() (RCC->APB2ENR |= RCC_APB2ENR_SPI1EN)
|
||||
#define SPI_0_CLKDIS() (RCC->APB2ENR &= ~(RCC_APB2ENR_SPI1EN))
|
||||
#define SPI_0_IRQ SPI1_IRQn
|
||||
#define SPI_0_ISR isr_spi1
|
||||
/* SPI 0 pin configuration */
|
||||
#define SPI_0_PORT_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOAEN)
|
||||
#define SPI_0_PORT GPIOA
|
||||
#define SPI_0_PIN_SCK 5
|
||||
#define SPI_0_PIN_MOSI 7
|
||||
#define SPI_0_PIN_MISO 6
|
||||
#define SPI_0_PIN_AF 5
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name I2C configuration
|
||||
* @{
|
||||
*/
|
||||
#define I2C_NUMOF (1U)
|
||||
#define I2C_0_EN 1
|
||||
#define I2C_IRQ_PRIO 1
|
||||
#define I2C_APBCLK (36000000U)
|
||||
|
||||
/* I2C 0 device configuration */
|
||||
#define I2C_0_DEV I2C1
|
||||
#define I2C_0_CLKEN() (RCC->APB1ENR |= RCC_APB1ENR_I2C1EN)
|
||||
#define I2C_0_CLKDIS() (RCC->APB1ENR &= ~(RCC_APB1ENR_I2C1EN))
|
||||
#define I2C_0_EVT_IRQ I2C1_EV_IRQn
|
||||
#define I2C_0_EVT_ISR isr_i2c1_ev
|
||||
#define I2C_0_ERR_IRQ I2C1_ER_IRQn
|
||||
#define I2C_0_ERR_ISR isr_i2c1_er
|
||||
/* I2C 0 pin configuration */
|
||||
#define I2C_0_PORT_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOBEN)
|
||||
#define I2C_0_PORT GPIOB
|
||||
#define I2C_0_SCL_PIN 8
|
||||
#define I2C_0_SCL_AF 4
|
||||
#define I2C_0_SDA_PIN 9
|
||||
#define I2C_0_SDA_AF 4
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __PERIPH_CONF_H */
|
||||
/** @} */
|
7
cpu/stm32l1/Makefile
Normal file
7
cpu/stm32l1/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# define the module that is build
|
||||
MODULE =cpu
|
||||
|
||||
# add a list of subdirectories, that should also be build
|
||||
DIRS += periph $(CORTEXM_COMMON)
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
25
cpu/stm32l1/Makefile.include
Normal file
25
cpu/stm32l1/Makefile.include
Normal file
@ -0,0 +1,25 @@
|
||||
# this CPU implementation is using the new core/CPU interface
|
||||
export CFLAGS += -DCOREIF_NG=1
|
||||
|
||||
# tell the build system that the CPU depends on the Cortex-M common files
|
||||
export USEMODULE += cortex-m3_common
|
||||
|
||||
# define path to cortex-m common module, which is needed for this CPU
|
||||
export CORTEXM_COMMON = $(RIOTCPU)/cortex-m3_common/
|
||||
|
||||
# define the linker script to use for this CPU
|
||||
export LINKERSCRIPT = $(RIOTCPU)/$(CPU)/$(CPU_MODEL)_linkerscript.ld
|
||||
|
||||
# include CPU specific includes
|
||||
export INCLUDES += -I$(RIOTCPU)/$(CPU)/include
|
||||
|
||||
# explicitly tell the linker to link the syscalls and startup code.
|
||||
# Without this the interrupt vectors will not be linked correctly!
|
||||
export UNDEF += $(BINDIR)cpu/syscalls.o
|
||||
export UNDEF += $(BINDIR)cpu/startup.o
|
||||
|
||||
# export the peripheral drivers to be linked into the final binary
|
||||
export USEMODULE += periph
|
||||
|
||||
# CPU depends on the cortex-m common module, so include it
|
||||
include $(CORTEXM_COMMON)Makefile.include
|
91
cpu/stm32l1/cpu.c
Normal file
91
cpu/stm32l1/cpu.c
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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_stm32l1
|
||||
* @{
|
||||
*
|
||||
* @file cpu.c
|
||||
* @brief Implementation of the kernel cpu functions
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "cpu.h"
|
||||
#include "board.h"
|
||||
#include "periph_conf.h"
|
||||
|
||||
static void clk_init(void);
|
||||
|
||||
void cpu_init(void)
|
||||
{
|
||||
/* set PendSV priority to the lowest possible priority */
|
||||
NVIC_SetPriority(PendSV_IRQn, 0xff);
|
||||
|
||||
/* initialize system clocks */
|
||||
clk_init();
|
||||
|
||||
/* configure the vector table location to internal flash */
|
||||
SCB->VTOR = FLASH_BASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure the clock system of the stm32f1
|
||||
*
|
||||
*/
|
||||
static void clk_init(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 interruptss */
|
||||
RCC->CIR = 0x0;
|
||||
|
||||
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration */
|
||||
/* Enable HSE */
|
||||
RCC->CR |= RCC_CR_HSION;
|
||||
/* Wait till HSE is ready,
|
||||
* NOTE: the MCU will stay here forever if no HSE clock is connected */
|
||||
while (!(RCC->CR & RCC_CR_HSIRDY));
|
||||
FLASH->ACR |= FLASH_ACR_ACC64;
|
||||
/* Enable Prefetch Buffer */
|
||||
FLASH->ACR |= FLASH_ACR_PRFTEN;
|
||||
/* Flash 1 wait state */
|
||||
FLASH->ACR |= CLOCK_FLASH_LATENCY;
|
||||
/* Power enable */
|
||||
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
|
||||
/* 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 = HSE / HSE_DIV * HSE_MUL */
|
||||
RCC->CFGR &= ~((uint32_t)(RCC_CFGR_PLLSRC | RCC_CFGR_PLLDIV | RCC_CFGR_PLLMUL));
|
||||
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI | CLOCK_PLL_HSE_DIV | CLOCK_PLL_HSE_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);
|
||||
}
|
75
cpu/stm32l1/hwtimer_arch.c
Normal file
75
cpu/stm32l1/hwtimer_arch.c
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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_stm32l1
|
||||
* @{
|
||||
*
|
||||
* @file hwtimer_arch.c
|
||||
* @brief Implementation of the kernels hwtimer interface
|
||||
*
|
||||
* The hardware timer implementation uses the Cortex build-in system timer as backend.
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "arch/hwtimer_arch.h"
|
||||
#include "thread.h"
|
||||
#include "board.h"
|
||||
#include "periph/timer.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
void irq_handler(int channel);
|
||||
void (*timeout_handler)(int);
|
||||
|
||||
|
||||
void hwtimer_arch_init(void (*handler)(int), uint32_t fcpu)
|
||||
{
|
||||
timeout_handler = handler;
|
||||
timer_init(HW_TIMER, 1, &irq_handler);
|
||||
}
|
||||
|
||||
void hwtimer_arch_enable_interrupt(void)
|
||||
{
|
||||
timer_irq_enable(HW_TIMER);
|
||||
}
|
||||
|
||||
void hwtimer_arch_disable_interrupt(void)
|
||||
{
|
||||
timer_irq_disable(HW_TIMER);
|
||||
}
|
||||
|
||||
void hwtimer_arch_set(unsigned long offset, short timer)
|
||||
{
|
||||
timer_set(HW_TIMER, timer, offset);
|
||||
}
|
||||
|
||||
void hwtimer_arch_set_absolute(unsigned long value, short timer)
|
||||
{
|
||||
timer_set_absolute(HW_TIMER, timer, value);
|
||||
}
|
||||
|
||||
void hwtimer_arch_unset(short timer)
|
||||
{
|
||||
timer_clear(HW_TIMER, timer);
|
||||
}
|
||||
|
||||
unsigned long hwtimer_arch_now(void)
|
||||
{
|
||||
return timer_read(HW_TIMER);
|
||||
}
|
||||
|
||||
void irq_handler(int channel)
|
||||
{
|
||||
timeout_handler((short)channel);
|
||||
}
|
79
cpu/stm32l1/include/cpu-conf.h
Normal file
79
cpu/stm32l1/include/cpu-conf.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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_stm32l1 stm32l1
|
||||
* @addtogroup cpu
|
||||
* @brief CPU specific implementations for the STM32F1
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Implementation specific CPU configuration options
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef CPUCONF_H_
|
||||
#define CPUCONF_H_
|
||||
|
||||
#include "stm32l1xx.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name Kernel configuration
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#define KERNEL_CONF_STACKSIZE_PRINTF (1024)
|
||||
|
||||
#ifndef KERNEL_CONF_STACKSIZE_DEFAULT
|
||||
#define KERNEL_CONF_STACKSIZE_DEFAULT (1024)
|
||||
#endif
|
||||
|
||||
#define KERNEL_CONF_STACKSIZE_IDLE (256)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name UART0 buffer size definition for compatibility reasons
|
||||
*
|
||||
* TODO: remove once the remodeling of the uart0 driver is done
|
||||
* @{
|
||||
*/
|
||||
#ifndef UART0_BUFSIZE
|
||||
#define UART0_BUFSIZE (128)
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Length for reading CPU_ID
|
||||
*/
|
||||
#define CPUID_ID_LEN (12)
|
||||
|
||||
/**
|
||||
* @name Definition of different panic modes
|
||||
*/
|
||||
typedef enum {
|
||||
HARD_FAULT,
|
||||
WATCHDOG,
|
||||
BUS_FAULT,
|
||||
USAGE_FAULT,
|
||||
DUMMY_HANDLER
|
||||
} panic_t;
|
||||
|
||||
#define TRANSCEIVER_BUFFER_SIZE (3)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __CPU_CONF_H */
|
||||
/** @} */
|
||||
/** @} */
|
41
cpu/stm32l1/include/hwtimer_cpu.h
Normal file
41
cpu/stm32l1/include/hwtimer_cpu.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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_stm32l1
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief CPU specific hwtimer configuration options
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef HWTIMER_CPU_H_
|
||||
#define HWTIMER_CPU_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name Hardware timer configuration
|
||||
* @{
|
||||
*/
|
||||
#define HWTIMER_MAXTIMERS (4) /**< the CPU implementation supports 4 HW timers */
|
||||
#define HWTIMER_SPEED (1000000U) /**< the HW timer runs with 1MHz */
|
||||
#define HWTIMER_MAXTICKS (0xFFFFFFFF) /**< 32-bit timer */
|
||||
#define HWTIMER_WAIT_OVERHEAD (3)
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HWTIMER_CPU_H_ */
|
||||
/** @} */
|
6677
cpu/stm32l1/include/stm32l1xx.h
Normal file
6677
cpu/stm32l1/include/stm32l1xx.h
Normal file
File diff suppressed because it is too large
Load Diff
53
cpu/stm32l1/lpm_arch.c
Normal file
53
cpu/stm32l1/lpm_arch.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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_stm32l1
|
||||
* @{
|
||||
*
|
||||
* @file lpm_arch.c
|
||||
* @brief Implementation of the kernel's lpm interface
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "arch/lpm_arch.h"
|
||||
|
||||
void lpm_arch_init(void)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
enum lpm_mode lpm_arch_set(enum lpm_mode target)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum lpm_mode lpm_arch_get(void)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lpm_arch_awake(void)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
void lpm_arch_begin_awake(void)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
void lpm_arch_end_awake(void)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
5
cpu/stm32l1/periph/Makefile
Normal file
5
cpu/stm32l1/periph/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
# define the module name
|
||||
MODULE = periph
|
||||
|
||||
# include RIOTs generic Makefile
|
||||
include $(RIOTBASE)/Makefile.base
|
31
cpu/stm32l1/periph/cpuid.c
Normal file
31
cpu/stm32l1/periph/cpuid.c
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2014 FU 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup driver_periph
|
||||
* @{
|
||||
*
|
||||
* @file cpuid.c
|
||||
* @brief Low-level CPUID driver implementation
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "cpu-conf.h"
|
||||
|
||||
#include "periph/cpuid.h"
|
||||
|
||||
#define STM32L1_CPUID_ADDR (0x1ff800d0)
|
||||
|
||||
void cpuid_get(void *id)
|
||||
{
|
||||
memcpy(id, (void *)(STM32L1_CPUID_ADDR), CPUID_ID_LEN);
|
||||
}
|
||||
|
||||
/** @} */
|
587
cpu/stm32l1/periph/gpio.c
Normal file
587
cpu/stm32l1/periph/gpio.c
Normal file
@ -0,0 +1,587 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup driver_periph
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level GPIO driver implementation
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "cpu.h"
|
||||
#include "sched.h"
|
||||
#include "thread.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "periph_conf.h"
|
||||
|
||||
/* guard file in case no GPIO devices are defined */
|
||||
#if GPIO_NUMOF
|
||||
|
||||
typedef struct {
|
||||
gpio_cb_t cb;
|
||||
void *arg;
|
||||
} gpio_state_t;
|
||||
|
||||
static gpio_state_t gpio_config[GPIO_NUMOF];
|
||||
|
||||
/* static port mappings */
|
||||
static GPIO_TypeDef *const gpio_port_map[GPIO_NUMOF] = {
|
||||
#if GPIO_0_EN
|
||||
[GPIO_0] = GPIO_0_PORT,
|
||||
#endif
|
||||
#if GPIO_1_EN
|
||||
[GPIO_1] = GPIO_1_PORT,
|
||||
#endif
|
||||
#if GPIO_2_EN
|
||||
[GPIO_2] = GPIO_2_PORT,
|
||||
#endif
|
||||
#if GPIO_3_EN
|
||||
[GPIO_3] = GPIO_3_PORT,
|
||||
#endif
|
||||
#if GPIO_4_EN
|
||||
[GPIO_4] = GPIO_4_PORT,
|
||||
#endif
|
||||
#if GPIO_5_EN
|
||||
[GPIO_5] = GPIO_5_PORT,
|
||||
#endif
|
||||
#if GPIO_6_EN
|
||||
[GPIO_6] = GPIO_6_PORT,
|
||||
#endif
|
||||
#if GPIO_7_EN
|
||||
[GPIO_7] = GPIO_7_PORT,
|
||||
#endif
|
||||
#if GPIO_8_EN
|
||||
[GPIO_8] = GPIO_8_PORT,
|
||||
#endif
|
||||
#if GPIO_9_EN
|
||||
[GPIO_9] = GPIO_9_PORT,
|
||||
#endif
|
||||
#if GPIO_10_EN
|
||||
[GPIO_10] = GPIO_10_PORT,
|
||||
#endif
|
||||
#if GPIO_11_EN
|
||||
[GPIO_11] = GPIO_11_PORT,
|
||||
#endif
|
||||
#if GPIO_12_EN
|
||||
[GPIO_12] = GPIO_12_PORT,
|
||||
#endif
|
||||
#if GPIO_13_EN
|
||||
[GPIO_13] = GPIO_13_PORT,
|
||||
#endif
|
||||
#if GPIO_14_EN
|
||||
[GPIO_14] = GPIO_14_PORT,
|
||||
#endif
|
||||
#if GPIO_15_EN
|
||||
[GPIO_15] = GPIO_15_PORT,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* static pin mappings */
|
||||
static const uint8_t gpio_pin_map[GPIO_NUMOF] = {
|
||||
#if GPIO_0_EN
|
||||
[GPIO_0] = GPIO_0_PIN,
|
||||
#endif
|
||||
#if GPIO_1_EN
|
||||
[GPIO_1] = GPIO_1_PIN,
|
||||
#endif
|
||||
#if GPIO_2_EN
|
||||
[GPIO_2] = GPIO_2_PIN,
|
||||
#endif
|
||||
#if GPIO_3_EN
|
||||
[GPIO_3] = GPIO_3_PIN,
|
||||
#endif
|
||||
#if GPIO_4_EN
|
||||
[GPIO_4] = GPIO_4_PIN,
|
||||
#endif
|
||||
#if GPIO_5_EN
|
||||
[GPIO_5] = GPIO_5_PIN,
|
||||
#endif
|
||||
#if GPIO_6_EN
|
||||
[GPIO_6] = GPIO_6_PIN,
|
||||
#endif
|
||||
#if GPIO_7_EN
|
||||
[GPIO_7] = GPIO_7_PIN,
|
||||
#endif
|
||||
#if GPIO_8_EN
|
||||
[GPIO_8] = GPIO_8_PIN,
|
||||
#endif
|
||||
#if GPIO_9_EN
|
||||
[GPIO_9] = GPIO_9_PIN,
|
||||
#endif
|
||||
#if GPIO_10_EN
|
||||
[GPIO_10] = GPIO_10_PIN,
|
||||
#endif
|
||||
#if GPIO_11_EN
|
||||
[GPIO_11] = GPIO_11_PIN,
|
||||
#endif
|
||||
#if GPIO_12_EN
|
||||
[GPIO_12] = GPIO_12_PIN,
|
||||
#endif
|
||||
#if GPIO_13_EN
|
||||
[GPIO_13] = GPIO_13_PIN,
|
||||
#endif
|
||||
#if GPIO_14_EN
|
||||
[GPIO_14] = GPIO_14_PIN,
|
||||
#endif
|
||||
#if GPIO_15_EN
|
||||
[GPIO_15] = GPIO_15_PIN,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* static irq mappings */
|
||||
static const IRQn_Type gpio_irq_map[GPIO_NUMOF] = {
|
||||
#if GPIO_0_EN
|
||||
[GPIO_0] = GPIO_0_IRQ,
|
||||
#endif
|
||||
#if GPIO_1_EN
|
||||
[GPIO_1] = GPIO_1_IRQ,
|
||||
#endif
|
||||
#if GPIO_2_EN
|
||||
[GPIO_2] = GPIO_2_IRQ,
|
||||
#endif
|
||||
#if GPIO_3_EN
|
||||
[GPIO_3] = GPIO_3_IRQ,
|
||||
#endif
|
||||
#if GPIO_4_EN
|
||||
[GPIO_4] = GPIO_4_IRQ,
|
||||
#endif
|
||||
#if GPIO_5_EN
|
||||
[GPIO_5] = GPIO_5_IRQ,
|
||||
#endif
|
||||
#if GPIO_6_EN
|
||||
[GPIO_6] = GPIO_6_IRQ,
|
||||
#endif
|
||||
#if GPIO_7_EN
|
||||
[GPIO_7] = GPIO_7_IRQ,
|
||||
#endif
|
||||
#if GPIO_8_EN
|
||||
[GPIO_8] = GPIO_8_IRQ,
|
||||
#endif
|
||||
#if GPIO_9_EN
|
||||
[GPIO_9] = GPIO_9_IRQ,
|
||||
#endif
|
||||
#if GPIO_10_EN
|
||||
[GPIO_10] = GPIO_10_IRQ,
|
||||
#endif
|
||||
#if GPIO_11_EN
|
||||
[GPIO_11] = GPIO_11_IRQ,
|
||||
#endif
|
||||
#if GPIO_12_EN
|
||||
[GPIO_12] = GPIO_12_IRQ,
|
||||
#endif
|
||||
#if GPIO_13_EN
|
||||
[GPIO_13] = GPIO_13_IRQ,
|
||||
#endif
|
||||
#if GPIO_14_EN
|
||||
[GPIO_14] = GPIO_14_IRQ,
|
||||
#endif
|
||||
#if GPIO_15_EN
|
||||
[GPIO_15] = GPIO_15_IRQ,
|
||||
#endif
|
||||
};
|
||||
|
||||
int gpio_init_out(gpio_t dev, gpio_pp_t pullup)
|
||||
{
|
||||
GPIO_TypeDef *port;
|
||||
uint8_t pin;
|
||||
|
||||
if (dev >= GPIO_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
port = gpio_port_map[dev];
|
||||
pin = gpio_pin_map[dev];
|
||||
|
||||
port->MODER &= ~(2 << (2 * pin)); /* set pin to output mode */
|
||||
port->MODER |= (1 << (2 * pin));
|
||||
port->OTYPER &= ~(1 << pin); /* set to push-pull configuration */
|
||||
port->OSPEEDR |= (3 << (2 * pin)); /* set to high speed */
|
||||
port->PUPDR &= ~(3 << (2 * pin)); /* configure push-pull resistors */
|
||||
port->PUPDR |= (pullup << (2 * pin));
|
||||
port->ODR &= ~(1 << pin); /* set pin to low signal */
|
||||
|
||||
return 0; /* all OK */
|
||||
}
|
||||
|
||||
int gpio_init_in(gpio_t dev, gpio_pp_t pullup)
|
||||
{
|
||||
GPIO_TypeDef *port;
|
||||
uint8_t pin;
|
||||
|
||||
if (dev >= GPIO_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
port = gpio_port_map[dev];
|
||||
pin = gpio_pin_map[dev];
|
||||
|
||||
port->MODER &= ~(3 << (2 * pin)); /* configure pin as input */
|
||||
port->PUPDR &= ~(3 << (2 * pin)); /* configure push-pull resistors */
|
||||
port->PUPDR |= (pullup << (2 * pin));
|
||||
|
||||
return 0; /* everything alright here */
|
||||
}
|
||||
|
||||
int gpio_init_int(gpio_t dev, gpio_pp_t pullup, gpio_flank_t flank, gpio_cb_t cb, void *arg)
|
||||
{
|
||||
int res;
|
||||
uint8_t pin;
|
||||
|
||||
if (dev >= GPIO_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pin = gpio_pin_map[dev];
|
||||
|
||||
/* configure pin as input */
|
||||
res = gpio_init_in(dev, pullup);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/* enable clock of the SYSCFG module for EXTI configuration */
|
||||
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
|
||||
|
||||
/* read pin number, set EXIT channel and enable global interrupt for EXTI channel */
|
||||
switch (dev) {
|
||||
#ifdef GPIO_0_EN
|
||||
case GPIO_0:
|
||||
GPIO_0_EXTI_CFG();
|
||||
break;
|
||||
#endif
|
||||
#ifdef GPIO_1_EN
|
||||
case GPIO_1:
|
||||
GPIO_1_EXTI_CFG();
|
||||
break;
|
||||
#endif
|
||||
#ifdef GPIO_2_EN
|
||||
case GPIO_2:
|
||||
GPIO_2_EXTI_CFG();
|
||||
break;
|
||||
#endif
|
||||
#ifdef GPIO_3_EN
|
||||
case GPIO_3:
|
||||
GPIO_3_EXTI_CFG();
|
||||
break;
|
||||
#endif
|
||||
#ifdef GPIO_4_EN
|
||||
case GPIO_4:
|
||||
GPIO_4_EXTI_CFG();
|
||||
break;
|
||||
#endif
|
||||
#ifdef GPIO_5_EN
|
||||
case GPIO_5:
|
||||
GPIO_5_EXTI_CFG();
|
||||
break;
|
||||
#endif
|
||||
#ifdef GPIO_6_EN
|
||||
case GPIO_6:
|
||||
GPIO_6_EXTI_CFG();
|
||||
break;
|
||||
#endif
|
||||
#ifdef GPIO_7_EN
|
||||
case GPIO_7:
|
||||
GPIO_7_EXTI_CFG();
|
||||
break;
|
||||
#endif
|
||||
#ifdef GPIO_8_EN
|
||||
case GPIO_8:
|
||||
GPIO_8_EXTI_CFG();
|
||||
break;
|
||||
#endif
|
||||
#ifdef GPIO_9_EN
|
||||
case GPIO_9:
|
||||
GPIO_9_EXTI_CFG();
|
||||
break;
|
||||
#endif
|
||||
#ifdef GPIO_10_EN
|
||||
case GPIO_10:
|
||||
GPIO_10_EXTI_CFG();
|
||||
break;
|
||||
#endif
|
||||
#ifdef GPIO_11_EN
|
||||
case GPIO_11:
|
||||
GPIO_11_EXTI_CFG();
|
||||
break;
|
||||
#endif
|
||||
#ifdef GPIO_12_EN
|
||||
case GPIO_12:
|
||||
GPIO_12_EXTI_CFG();
|
||||
break;
|
||||
#endif
|
||||
#ifdef GPIO_13_EN
|
||||
case GPIO_13:
|
||||
GPIO_13_EXTI_CFG();
|
||||
break;
|
||||
#endif
|
||||
#ifdef GPIO_14_EN
|
||||
case GPIO_14:
|
||||
GPIO_14_EXTI_CFG();
|
||||
break;
|
||||
#endif
|
||||
#ifdef GPIO_15_EN
|
||||
case GPIO_15:
|
||||
GPIO_15_EXTI_CFG();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
NVIC_EnableIRQ(gpio_irq_map[dev]);
|
||||
|
||||
/* set callback */
|
||||
gpio_config[dev].cb = cb;
|
||||
gpio_config[dev].arg = arg;
|
||||
|
||||
/* configure the event that triggers an interrupt */
|
||||
switch (flank) {
|
||||
case GPIO_RISING:
|
||||
EXTI->RTSR |= (1 << pin);
|
||||
EXTI->FTSR &= ~(1 << pin);
|
||||
break;
|
||||
case GPIO_FALLING:
|
||||
EXTI->RTSR &= ~(1 << pin);
|
||||
EXTI->FTSR |= (1 << pin);
|
||||
break;
|
||||
case GPIO_BOTH:
|
||||
EXTI->RTSR |= (1 << pin);
|
||||
EXTI->FTSR |= (1 << pin);
|
||||
break;
|
||||
}
|
||||
|
||||
/* clear any pending requests */
|
||||
EXTI->PR = (1 << pin);
|
||||
/* unmask the pins interrupt channel */
|
||||
EXTI->IMR |= (1 << pin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gpio_irq_enable(gpio_t dev)
|
||||
{
|
||||
uint8_t pin;
|
||||
|
||||
if (dev >= GPIO_NUMOF) {
|
||||
return;
|
||||
}
|
||||
|
||||
pin = gpio_pin_map[dev];
|
||||
EXTI->IMR |= (1 << pin);
|
||||
}
|
||||
|
||||
void gpio_irq_disable(gpio_t dev)
|
||||
{
|
||||
uint8_t pin;
|
||||
|
||||
if (dev >= GPIO_NUMOF) {
|
||||
return;
|
||||
}
|
||||
|
||||
pin = gpio_pin_map[dev];
|
||||
EXTI->IMR &= ~(1 << pin);
|
||||
}
|
||||
|
||||
int gpio_read(gpio_t dev)
|
||||
{
|
||||
GPIO_TypeDef *port;
|
||||
uint8_t pin;
|
||||
|
||||
if (dev >= GPIO_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
port = gpio_port_map[dev];
|
||||
pin = gpio_pin_map[dev];
|
||||
|
||||
if (port->MODER & (1 << (pin * 2))) { /* if configured as output */
|
||||
return port->ODR & (1 << pin); /* read output data register */
|
||||
} else {
|
||||
return port->IDR & (1 << pin); /* else read input data register */
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_set(gpio_t dev)
|
||||
{
|
||||
GPIO_TypeDef *port;
|
||||
uint8_t pin;
|
||||
|
||||
if (dev >= GPIO_NUMOF) {
|
||||
return;
|
||||
}
|
||||
|
||||
port = gpio_port_map[dev];
|
||||
pin = gpio_pin_map[dev];
|
||||
|
||||
port->ODR |= (1 << pin);
|
||||
}
|
||||
|
||||
void gpio_clear(gpio_t dev)
|
||||
{
|
||||
GPIO_TypeDef *port;
|
||||
uint8_t pin;
|
||||
|
||||
if (dev >= GPIO_NUMOF) {
|
||||
return;
|
||||
}
|
||||
|
||||
port = gpio_port_map[dev];
|
||||
pin = gpio_pin_map[dev];
|
||||
|
||||
port->ODR &= ~(1 << pin);
|
||||
}
|
||||
|
||||
void gpio_toggle(gpio_t dev)
|
||||
{
|
||||
if (gpio_read(dev)) {
|
||||
gpio_clear(dev);
|
||||
} else {
|
||||
gpio_set(dev);
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_write(gpio_t dev, int value)
|
||||
{
|
||||
if (value) {
|
||||
gpio_set(dev);
|
||||
} else {
|
||||
gpio_clear(dev);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GPIO_IRQ_0
|
||||
void isr_exti0(void)
|
||||
{
|
||||
if (EXTI->PR & EXTI_PR_PR0) {
|
||||
EXTI->PR |= EXTI_PR_PR0; /* clear status bit by writing a 1 to it */
|
||||
gpio_config[GPIO_IRQ_0].cb(gpio_config[GPIO_IRQ_0].arg);
|
||||
}
|
||||
if (sched_context_switch_request) {
|
||||
thread_yield();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GPIO_IRQ_1
|
||||
void isr_exti1(void)
|
||||
{
|
||||
if (EXTI->PR & EXTI_PR_PR1) {
|
||||
EXTI->PR |= EXTI_PR_PR1; /* clear status bit by writing a 1 to it */
|
||||
gpio_config[GPIO_IRQ_1].cb(gpio_config[GPIO_IRQ_1].arg);
|
||||
}
|
||||
if (sched_context_switch_request) {
|
||||
thread_yield();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GPIO_IRQ_2
|
||||
void isr_exti2(void)
|
||||
{
|
||||
if (EXTI->PR & EXTI_PR_PR2) {
|
||||
EXTI->PR |= EXTI_PR_PR2; /* clear status bit by writing a 1 to it */
|
||||
gpio_config[GPIO_IRQ_2].cb(gpio_config[GPIO_IRQ_2].arg);
|
||||
}
|
||||
if (sched_context_switch_request) {
|
||||
thread_yield();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GPIO_IRQ_3
|
||||
void isr_exti3(void)
|
||||
{
|
||||
if (EXTI->PR & EXTI_PR_PR3) {
|
||||
EXTI->PR |= EXTI_PR_PR3; /* clear status bit by writing a 1 to it */
|
||||
gpio_config[GPIO_IRQ_3].cb(gpio_config[GPIO_IRQ_3].arg);
|
||||
}
|
||||
if (sched_context_switch_request) {
|
||||
thread_yield();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GPIO_IRQ_4
|
||||
void isr_exti4(void)
|
||||
{
|
||||
if (EXTI->PR & EXTI_PR_PR4) {
|
||||
EXTI->PR |= EXTI_PR_PR4; /* clear status bit by writing a 1 to it */
|
||||
gpio_config[GPIO_IRQ_4].cb(gpio_config[GPIO_IRQ_4].arg);
|
||||
}
|
||||
if (sched_context_switch_request) {
|
||||
thread_yield();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(GPIO_IRQ_5) || defined(GPIO_IRQ_6) || defined(GPIO_IRQ_7) || defined(GPIO_IRQ_8) || defined(GPIO_IRQ_9)
|
||||
void isr_exti9_5(void)
|
||||
{
|
||||
if (EXTI->PR & EXTI_PR_PR5) {
|
||||
EXTI->PR |= EXTI_PR_PR5; /* clear status bit by writing a 1 to it */
|
||||
gpio_config[GPIO_IRQ_5].cb(gpio_config[GPIO_IRQ_5].arg);
|
||||
}
|
||||
else if (EXTI->PR & EXTI_PR_PR6) {
|
||||
EXTI->PR |= EXTI_PR_PR6; /* clear status bit by writing a 1 to it */
|
||||
gpio_config[GPIO_IRQ_6].cb(gpio_config[GPIO_IRQ_6].arg);
|
||||
}
|
||||
else if (EXTI->PR & EXTI_PR_PR7) {
|
||||
EXTI->PR |= EXTI_PR_PR7; /* clear status bit by writing a 1 to it */
|
||||
gpio_config[GPIO_IRQ_7].cb(gpio_config[GPIO_IRQ_7].arg);
|
||||
}
|
||||
else if (EXTI->PR & EXTI_PR_PR8) {
|
||||
EXTI->PR |= EXTI_PR_PR8; /* clear status bit by writing a 1 to it */
|
||||
gpio_config[GPIO_IRQ_8].cb(gpio_config[GPIO_IRQ_8].arg);
|
||||
}
|
||||
else if (EXTI->PR & EXTI_PR_PR9) {
|
||||
EXTI->PR |= EXTI_PR_PR9; /* clear status bit by writing a 1 to it */
|
||||
gpio_config[GPIO_IRQ_9].cb(gpio_config[GPIO_IRQ_9].arg);
|
||||
}
|
||||
if (sched_context_switch_request) {
|
||||
thread_yield();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(GPIO_IRQ_10) || defined(GPIO_IRQ_11) || defined(GPIO_IRQ_12) || defined(GPIO_IRQ_13) || defined(GPIO_IRQ_14) || defined(GPIO_IRQ_15)
|
||||
void isr_exti15_10(void)
|
||||
{
|
||||
if (EXTI->PR & EXTI_PR_PR10) {
|
||||
EXTI->PR |= EXTI_PR_PR10; /* clear status bit by writing a 1 to it */
|
||||
gpio_config[GPIO_IRQ_10].cb(gpio_config[GPIO_IRQ_10].arg);
|
||||
}
|
||||
else if (EXTI->PR & EXTI_PR_PR11) {
|
||||
EXTI->PR |= EXTI_PR_PR11; /* clear status bit by writing a 1 to it */
|
||||
gpio_config[GPIO_IRQ_11].cb(gpio_config[GPIO_IRQ_11].arg);
|
||||
}
|
||||
else if (EXTI->PR & EXTI_PR_PR12) {
|
||||
EXTI->PR |= EXTI_PR_PR12; /* clear status bit by writing a 1 to it */
|
||||
gpio_config[GPIO_IRQ_12].cb(gpio_config[GPIO_IRQ_12].arg);
|
||||
}
|
||||
else if (EXTI->PR & EXTI_PR_PR13) {
|
||||
EXTI->PR |= EXTI_PR_PR13; /* clear status bit by writing a 1 to it */
|
||||
gpio_config[GPIO_IRQ_13].cb(gpio_config[GPIO_IRQ_13].arg);
|
||||
}
|
||||
else if (EXTI->PR & EXTI_PR_PR14) {
|
||||
EXTI->PR |= EXTI_PR_PR14; /* clear status bit by writing a 1 to it */
|
||||
gpio_config[GPIO_IRQ_14].cb(gpio_config[GPIO_IRQ_14].arg);
|
||||
}
|
||||
else if (EXTI->PR & EXTI_PR_PR15) {
|
||||
EXTI->PR |= EXTI_PR_PR15; /* clear status bit by writing a 1 to it */
|
||||
gpio_config[GPIO_IRQ_15].cb(gpio_config[GPIO_IRQ_15].arg);
|
||||
}
|
||||
if (sched_context_switch_request) {
|
||||
thread_yield();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GPIO_NUMOF */
|
543
cpu/stm32l1/periph/i2c.c
Normal file
543
cpu/stm32l1/periph/i2c.c
Normal file
@ -0,0 +1,543 @@
|
||||
/*
|
||||
* Copyright (C) 2014 FU 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup driver_periph
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level I2C driver implementation
|
||||
*
|
||||
* @note This implementation only implements the 7-bit addressing 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>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#include "cpu.h"
|
||||
#include "periph/i2c.h"
|
||||
#include "periph_conf.h"
|
||||
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/* guard file in case no I2C device is defined */
|
||||
#if I2C_NUMOF
|
||||
|
||||
/* static function definitions */
|
||||
static void _i2c_init(I2C_TypeDef *i2c, int ccr);
|
||||
static void _toggle_pins(GPIO_TypeDef *port, int pin_scl, int pin_sda);
|
||||
static void _pin_config(GPIO_TypeDef *port, int pin_scl, int pin_sda);
|
||||
static void _start(I2C_TypeDef *dev, uint8_t address, uint8_t rw_flag);
|
||||
static inline void _clear_addr(I2C_TypeDef *dev);
|
||||
static inline void _write(I2C_TypeDef *dev, char *data, int length);
|
||||
static inline void _stop(I2C_TypeDef *dev);
|
||||
|
||||
int i2c_init_master(i2c_t dev, i2c_speed_t speed)
|
||||
{
|
||||
I2C_TypeDef *i2c;
|
||||
GPIO_TypeDef *port;
|
||||
int pin_scl = 0, pin_sda = 0;
|
||||
int ccr;
|
||||
|
||||
/* read speed configuration */
|
||||
switch (speed) {
|
||||
case I2C_SPEED_NORMAL:
|
||||
ccr = I2C_APBCLK / 200000;
|
||||
break;
|
||||
|
||||
case I2C_SPEED_FAST:
|
||||
ccr = I2C_APBCLK / 800000;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* read static device configuration */
|
||||
switch (dev) {
|
||||
#if I2C_0_EN
|
||||
case I2C_0:
|
||||
i2c = I2C_0_DEV;
|
||||
port = I2C_0_PORT;
|
||||
pin_scl = I2C_0_SCL_PIN;
|
||||
pin_sda = I2C_0_SDA_PIN;
|
||||
I2C_0_CLKEN();
|
||||
I2C_0_PORT_CLKEN();
|
||||
NVIC_SetPriority(I2C_0_ERR_IRQ, I2C_IRQ_PRIO);
|
||||
NVIC_EnableIRQ(I2C_0_ERR_IRQ);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* configure pins */
|
||||
_pin_config(port, pin_scl, pin_sda);
|
||||
|
||||
/* configure device */
|
||||
_i2c_init(i2c, ccr);
|
||||
|
||||
/* make sure the analog filters don't hang -> see errata sheet 2.14.7 */
|
||||
if (i2c->SR2 & I2C_SR2_BUSY) {
|
||||
DEBUG("LINE BUSY AFTER RESET -> toggle pins now\n");
|
||||
/* disable peripheral */
|
||||
i2c->CR1 &= ~I2C_CR1_PE;
|
||||
/* toggle both pins to reset analog filter */
|
||||
_toggle_pins(port, pin_scl, pin_sda);
|
||||
/* reset pins for alternate function */
|
||||
_pin_config(port, pin_scl, pin_sda);
|
||||
/* make peripheral soft reset */
|
||||
i2c->CR1 |= I2C_CR1_SWRST;
|
||||
i2c->CR1 &= ~I2C_CR1_SWRST;
|
||||
/* enable device */
|
||||
_i2c_init(i2c, ccr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _i2c_init(I2C_TypeDef *i2c, int ccr)
|
||||
{
|
||||
/* disable device and set ACK bit */
|
||||
i2c->CR1 = I2C_CR1_ACK;
|
||||
/* configure I2C clock */
|
||||
i2c->CR2 = (I2C_APBCLK / 1000000) | I2C_CR2_ITERREN;
|
||||
i2c->CCR = ccr;
|
||||
i2c->TRISE = (I2C_APBCLK / 1000000) + 1;
|
||||
/* configure device */
|
||||
i2c->OAR1 = 0; /* makes sure we are in 7-bit address mode */
|
||||
/* enable device */
|
||||
i2c->CR1 |= I2C_CR1_PE;
|
||||
}
|
||||
|
||||
static void _pin_config(GPIO_TypeDef *port, int pin_scl, int pin_sda)
|
||||
{
|
||||
/* Set GPIOs to AF mode */
|
||||
port->MODER &= ~(3 << (2 * pin_scl));
|
||||
port->MODER |= (2 << (2 * pin_scl));
|
||||
port->MODER &= ~(3 << (2 * pin_sda));
|
||||
port->MODER |= (2 << (2 * pin_sda));
|
||||
|
||||
/* Set speed high*/
|
||||
port->OSPEEDR |= (3 << (2 * pin_scl));
|
||||
port->OSPEEDR |= (3 << (2 * pin_sda));
|
||||
|
||||
/* Set to push-pull configuration open drain*/
|
||||
port->OTYPER |= (1 << pin_scl);
|
||||
port->OTYPER |= (1 << pin_sda);
|
||||
|
||||
/* Enable pull-up resistors */
|
||||
port->PUPDR &= ~(3 << (2 * pin_scl));
|
||||
port->PUPDR |= (1 << (2 * pin_scl));
|
||||
port->PUPDR &= ~(3 << (2 * pin_sda));
|
||||
port->PUPDR |= (1 << (2 * pin_sda));
|
||||
|
||||
/* Configure GPIOs to for the I2C alternate function */
|
||||
if (pin_scl < 8) {
|
||||
port->AFR[0] &= ~(0xf << (4 * pin_scl));
|
||||
port->AFR[0] |= (I2C_0_SCL_AF << (4 * pin_scl));
|
||||
}
|
||||
else {
|
||||
port->AFR[1] &= ~(0xf << (4 * (pin_scl - 8)));
|
||||
port->AFR[1] |= (I2C_0_SCL_AF << (4 * (pin_scl - 8)));
|
||||
}
|
||||
|
||||
if (pin_sda < 8) {
|
||||
port->AFR[0] &= ~(0xf << (4 * pin_sda));
|
||||
port->AFR[0] |= (I2C_0_SDA_AF << (4 * pin_sda));
|
||||
}
|
||||
else {
|
||||
port->AFR[1] &= ~(0xf << (4 * (pin_sda - 8)));
|
||||
port->AFR[1] |= (I2C_0_SDA_AF << (4 * (pin_sda - 8)));
|
||||
}
|
||||
}
|
||||
|
||||
static void _toggle_pins(GPIO_TypeDef *port, int pin_scl, int pin_sda)
|
||||
{
|
||||
/* Set GPIOs to General purpose output mode mode */
|
||||
port->MODER &= ~(3 << (2 * pin_scl));
|
||||
port->MODER |= (1 << (2 * pin_scl));
|
||||
port->MODER &= ~(3 << (2 * pin_sda));
|
||||
port->MODER |= (1 << (2 * pin_sda));
|
||||
|
||||
/* Set speed high*/
|
||||
port->OSPEEDR |= (3 << (2 * pin_scl));
|
||||
port->OSPEEDR |= (3 << (2 * pin_sda));
|
||||
|
||||
/* Set to push-pull configuration open drain*/
|
||||
port->OTYPER |= (1 << pin_scl);
|
||||
port->OTYPER |= (1 << pin_sda);
|
||||
|
||||
/* set both to high */
|
||||
port->ODR |= (1 << pin_scl);
|
||||
port->ODR |= (1 << pin_sda);
|
||||
/* set SDA to low */
|
||||
port->ODR &= ~(1 << pin_sda);
|
||||
/* set SCL to low */
|
||||
port->ODR &= ~(1 << pin_scl);
|
||||
/* set SCL to high */
|
||||
port->ODR |= (1 << pin_scl);
|
||||
/* set SDA to high */
|
||||
port->ODR |= (1 << pin_sda);
|
||||
}
|
||||
|
||||
int i2c_init_slave(i2c_t dev, uint8_t address)
|
||||
{
|
||||
/* TODO: implement slave mode */
|
||||
return -1;
|
||||
}
|
||||
|
||||
int i2c_read_byte(i2c_t dev, uint8_t address, char *data)
|
||||
{
|
||||
return i2c_read_bytes(dev, address, data, 1);
|
||||
}
|
||||
|
||||
int i2c_read_bytes(i2c_t dev, uint8_t address, char *data, int length)
|
||||
{
|
||||
unsigned int state;
|
||||
int i = 0;
|
||||
I2C_TypeDef *i2c;
|
||||
|
||||
switch (dev) {
|
||||
#if I2C_0_EN
|
||||
case I2C_0:
|
||||
i2c = I2C_0_DEV;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (length) {
|
||||
case 1:
|
||||
DEBUG("Send Slave address and wait for ADDR == 1\n");
|
||||
_start(i2c, address, I2C_FLAG_READ);
|
||||
|
||||
DEBUG("Set ACK = 0\n");
|
||||
i2c->CR1 &= ~(I2C_CR1_ACK);
|
||||
|
||||
DEBUG("Clear ADDR and set STOP = 1\n");
|
||||
state = disableIRQ();
|
||||
_clear_addr(i2c);
|
||||
i2c->CR1 |= (I2C_CR1_STOP);
|
||||
restoreIRQ(state);
|
||||
|
||||
DEBUG("Wait for RXNE == 1\n");
|
||||
|
||||
while (!(i2c->SR1 & I2C_SR1_RXNE));
|
||||
|
||||
DEBUG("Read received data\n");
|
||||
*data = (char)i2c->DR;
|
||||
|
||||
/* wait until STOP is cleared by hardware */
|
||||
while (i2c->CR1 & I2C_CR1_STOP);
|
||||
|
||||
/* reset ACK to be able to receive new data */
|
||||
i2c->CR1 |= (I2C_CR1_ACK);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
DEBUG("Send Slave address and wait for ADDR == 1\n");
|
||||
_start(i2c, address, I2C_FLAG_READ);
|
||||
DEBUG("Set POS bit\n");
|
||||
i2c->CR1 |= (I2C_CR1_POS | I2C_CR1_ACK);
|
||||
DEBUG("Crit block: Clear ADDR bit and clear ACK flag\n");
|
||||
state = disableIRQ();
|
||||
_clear_addr(i2c);
|
||||
i2c->CR1 &= ~(I2C_CR1_ACK);
|
||||
restoreIRQ(state);
|
||||
|
||||
DEBUG("Wait for transfer to be completed\n");
|
||||
|
||||
while (!(i2c->SR1 & I2C_SR1_BTF));
|
||||
|
||||
DEBUG("Crit block: set STOP and read first byte\n");
|
||||
state = disableIRQ();
|
||||
i2c->CR1 |= (I2C_CR1_STOP);
|
||||
data[0] = (char)i2c->DR;
|
||||
restoreIRQ(state);
|
||||
|
||||
DEBUG("read second byte\n");
|
||||
data[1] = (char)i2c->DR;
|
||||
|
||||
DEBUG("wait for STOP bit to be cleared again\n");
|
||||
|
||||
while (i2c->CR1 & I2C_CR1_STOP);
|
||||
|
||||
DEBUG("reset POS = 0 and ACK = 1\n");
|
||||
i2c->CR1 &= ~(I2C_CR1_POS);
|
||||
i2c->CR1 |= (I2C_CR1_ACK);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG("Send Slave address and wait for ADDR == 1\n");
|
||||
_start(i2c, address, I2C_FLAG_READ);
|
||||
_clear_addr(i2c);
|
||||
|
||||
while (i < (length - 3)) {
|
||||
DEBUG("Wait until byte was received\n");
|
||||
|
||||
while (!(i2c->SR1 & I2C_SR1_RXNE));
|
||||
|
||||
DEBUG("Copy byte from DR\n");
|
||||
data[i++] = (char)i2c->DR;
|
||||
}
|
||||
|
||||
DEBUG("Reading the last 3 bytes, waiting for BTF flag\n");
|
||||
|
||||
while (!(i2c->SR1 & I2C_SR1_BTF));
|
||||
|
||||
DEBUG("Disable ACK\n");
|
||||
i2c->CR1 &= ~(I2C_CR1_ACK);
|
||||
|
||||
DEBUG("Crit block: set STOP and read N-2 byte\n");
|
||||
state = disableIRQ();
|
||||
data[i++] = (char)i2c->DR;
|
||||
i2c->CR1 |= (I2C_CR1_STOP);
|
||||
restoreIRQ(state);
|
||||
|
||||
DEBUG("Read N-1 byte\n");
|
||||
data[i++] = (char)i2c->DR;
|
||||
|
||||
while (!(i2c->SR1 & I2C_SR1_RXNE));
|
||||
|
||||
DEBUG("Read last byte\n");
|
||||
|
||||
data[i++] = (char)i2c->DR;
|
||||
|
||||
DEBUG("wait for STOP bit to be cleared again\n");
|
||||
|
||||
while (i2c->CR1 & I2C_CR1_STOP);
|
||||
|
||||
DEBUG("reset POS = 0 and ACK = 1\n");
|
||||
i2c->CR1 &= ~(I2C_CR1_POS);
|
||||
i2c->CR1 |= (I2C_CR1_ACK);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
int i2c_read_reg(i2c_t dev, uint8_t address, uint8_t reg, char *data)
|
||||
{
|
||||
return i2c_read_regs(dev, address, reg, data, 1);
|
||||
}
|
||||
|
||||
int i2c_read_regs(i2c_t dev, uint8_t address, uint8_t reg, char *data, int length)
|
||||
{
|
||||
I2C_TypeDef *i2c;
|
||||
|
||||
switch (dev) {
|
||||
#if I2C_0_EN
|
||||
case I2C_0:
|
||||
i2c = I2C_0_DEV;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* send start condition and slave address */
|
||||
DEBUG("Send slave address and clear ADDR flag\n");
|
||||
_start(i2c, address, I2C_FLAG_WRITE);
|
||||
_clear_addr(i2c);
|
||||
DEBUG("Write reg into DR\n");
|
||||
i2c->DR = reg;
|
||||
_stop(i2c);
|
||||
DEBUG("Now start a read transaction\n");
|
||||
return i2c_read_bytes(dev, address, data, length);
|
||||
}
|
||||
|
||||
int i2c_write_byte(i2c_t dev, uint8_t address, char data)
|
||||
{
|
||||
return i2c_write_bytes(dev, address, &data, 1);
|
||||
}
|
||||
|
||||
int i2c_write_bytes(i2c_t dev, uint8_t address, char *data, int length)
|
||||
{
|
||||
I2C_TypeDef *i2c;
|
||||
|
||||
switch (dev) {
|
||||
#if I2C_0_EN
|
||||
case I2C_0:
|
||||
i2c = I2C_0_DEV;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* start transmission and send slave address */
|
||||
DEBUG("sending start sequence\n");
|
||||
_start(i2c, address, I2C_FLAG_WRITE);
|
||||
_clear_addr(i2c);
|
||||
/* send out data bytes */
|
||||
_write(i2c, data, length);
|
||||
/* end transmission */
|
||||
DEBUG("Ending transmission\n");
|
||||
_stop(i2c);
|
||||
DEBUG("STOP condition was send out\n");
|
||||
return length;
|
||||
}
|
||||
|
||||
int i2c_write_reg(i2c_t dev, uint8_t address, uint8_t reg, char data)
|
||||
{
|
||||
return i2c_write_regs(dev, address, reg, &data, 1);
|
||||
}
|
||||
|
||||
int i2c_write_regs(i2c_t dev, uint8_t address, uint8_t reg, char *data, int length)
|
||||
{
|
||||
I2C_TypeDef *i2c;
|
||||
|
||||
switch (dev) {
|
||||
#if I2C_0_EN
|
||||
case I2C_0:
|
||||
i2c = I2C_0_DEV;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* start transmission and send slave address */
|
||||
_start(i2c, address, I2C_FLAG_WRITE);
|
||||
_clear_addr(i2c);
|
||||
/* send register address and wait for complete transfer to be finished*/
|
||||
_write(i2c, (char *)(®), 1);
|
||||
/* write data to register */
|
||||
_write(i2c, data, length);
|
||||
/* finish transfer */
|
||||
_stop(i2c);
|
||||
/* return number of bytes send */
|
||||
return length;
|
||||
}
|
||||
|
||||
void i2c_poweron(i2c_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if I2C_0_EN
|
||||
case I2C_0:
|
||||
I2C_0_CLKEN();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void i2c_poweroff(i2c_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if I2C_0_EN
|
||||
case I2C_0:
|
||||
while (I2C_0_DEV->SR2 & I2C_SR2_BUSY);
|
||||
|
||||
I2C_0_CLKDIS();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void _start(I2C_TypeDef *dev, uint8_t address, uint8_t rw_flag)
|
||||
{
|
||||
/* wait for device to be ready */
|
||||
DEBUG("Wait for device to be ready\n");
|
||||
|
||||
while (dev->SR2 & I2C_SR2_BUSY);
|
||||
|
||||
/* generate start condition */
|
||||
DEBUG("Generate start condition\n");
|
||||
dev->CR1 |= I2C_CR1_START;
|
||||
DEBUG("Wait for SB flag to be set\n");
|
||||
|
||||
while (!(dev->SR1 & I2C_SR1_SB));
|
||||
|
||||
/* send address and read/write flag */
|
||||
DEBUG("Send address\n");
|
||||
dev->DR = (address << 1) | rw_flag;
|
||||
/* clear ADDR flag by reading first SR1 and then SR2 */
|
||||
DEBUG("Wait for ADDR flag to be set\n");
|
||||
|
||||
while (!(dev->SR1 & I2C_SR1_ADDR));
|
||||
}
|
||||
|
||||
static inline void _clear_addr(I2C_TypeDef *dev)
|
||||
{
|
||||
dev->SR1;
|
||||
dev->SR2;
|
||||
DEBUG("Cleared address\n");
|
||||
}
|
||||
|
||||
static inline void _write(I2C_TypeDef *dev, char *data, int length)
|
||||
{
|
||||
DEBUG("Looping through bytes\n");
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
/* write data to data register */
|
||||
dev->DR = (uint8_t)data[i];
|
||||
DEBUG("Written %i byte to data reg, now waiting for DR to be empty again\n", i);
|
||||
|
||||
/* wait for transfer to finish */
|
||||
while (!(dev->SR1 & I2C_SR1_TXE));
|
||||
|
||||
DEBUG("DR is now empty again\n");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _stop(I2C_TypeDef *dev)
|
||||
{
|
||||
/* make sure last byte was send */
|
||||
DEBUG("Wait if last byte hasn't been sent\n");
|
||||
|
||||
while (!(dev->SR1 & I2C_SR1_BTF));
|
||||
|
||||
/* send STOP condition */
|
||||
dev->CR1 |= I2C_CR1_STOP;
|
||||
}
|
||||
|
||||
#if I2C_0_EN
|
||||
void I2C_0_ERR_ISR(void)
|
||||
{
|
||||
unsigned state = I2C_0_DEV->SR1;
|
||||
DEBUG("\n\n### I2C ERROR OCCURED ###\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");
|
||||
}
|
||||
while (1);
|
||||
}
|
||||
#endif /* I2C_0_EN */
|
||||
|
||||
#endif /* I2C_NUMOF */
|
257
cpu/stm32l1/periph/spi.c
Normal file
257
cpu/stm32l1/periph/spi.c
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup driver_periph
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level SPI driver implementation
|
||||
*
|
||||
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
|
||||
* @author Hauke Petersen <mail@haukepetersen.de>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "cpu.h"
|
||||
#include "periph/spi.h"
|
||||
#include "periph_conf.h"
|
||||
#include "thread.h"
|
||||
#include "sched.h"
|
||||
|
||||
/* guard file in case no SPI device is defined */
|
||||
#if SPI_NUMOF
|
||||
|
||||
int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
|
||||
{
|
||||
SPI_TypeDef *spi;
|
||||
|
||||
/* power on the SPI device */
|
||||
spi_poweron(dev);
|
||||
|
||||
switch (dev) {
|
||||
#if SPI_0_EN
|
||||
case SPI_0:
|
||||
spi = SPI_0_DEV;
|
||||
SPI_0_PORT_CLKEN();
|
||||
break;
|
||||
#endif
|
||||
#if SPI_1_EN
|
||||
case SPI_1:
|
||||
spi = SPI_1_DEV;
|
||||
SPI_1_PORT_CLKEN();
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* configure SCK, MISO and MOSI pin */
|
||||
spi_conf_pins(dev);
|
||||
|
||||
/* reset SPI configuration registers */
|
||||
spi->CR1 = 0;
|
||||
spi->CR2 = 0;
|
||||
spi->I2SCFGR = 0; /* this makes sure SPI mode is selected */
|
||||
|
||||
/* configure bus clock speed */
|
||||
switch (speed) {
|
||||
case SPI_SPEED_100KHZ:
|
||||
spi->CR1 |= (7 << 3); /* actual clock: 125KHz (lowest possible) */
|
||||
break;
|
||||
case SPI_SPEED_400KHZ:
|
||||
spi->CR1 |= (5 << 3); /* actual clock: 500KHz */
|
||||
break;
|
||||
case SPI_SPEED_1MHZ:
|
||||
spi->CR1 |= (4 << 3); /* actual clock: 1MHz */
|
||||
break;
|
||||
case SPI_SPEED_5MHZ:
|
||||
spi->CR1 |= (2 << 3); /* actual clock: 4MHz */
|
||||
break;
|
||||
case SPI_SPEED_10MHZ:
|
||||
spi->CR1 |= (1 << 3); /* actual clock 8MHz */
|
||||
}
|
||||
|
||||
/* select clock polarity and clock phase */
|
||||
spi->CR1 |= conf;
|
||||
/* select master mode */
|
||||
spi->CR1 |= SPI_CR1_MSTR;
|
||||
/* the NSS (chip select) is managed purely by software */
|
||||
spi->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI;
|
||||
/* enable the SPI device */
|
||||
spi->CR1 |= SPI_CR1_SPE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data))
|
||||
{
|
||||
/* due to issues with the send buffer, the slave mode is not (yet) supported */
|
||||
return -1;
|
||||
}
|
||||
|
||||
int spi_conf_pins(spi_t dev)
|
||||
{
|
||||
GPIO_TypeDef *port;
|
||||
int pin[3]; /* 3 pins: sck, miso, mosi */
|
||||
int af = 0;
|
||||
|
||||
switch (dev) {
|
||||
#if SPI_0_EN
|
||||
case SPI_0:
|
||||
port = SPI_0_PORT;
|
||||
pin[0] = SPI_0_PIN_SCK;
|
||||
pin[1] = SPI_0_PIN_MISO;
|
||||
pin[2] = SPI_0_PIN_MOSI;
|
||||
af = SPI_0_PIN_AF;
|
||||
break;
|
||||
#endif
|
||||
#if SPI_1_EN
|
||||
case SPI_1:
|
||||
port = SPI_1_PORT;
|
||||
pin[0] = SPI_1_PIN_SCK;
|
||||
pin[1] = SPI_1_PIN_MISO;
|
||||
pin[2] = SPI_1_PIN_MOSI;
|
||||
af = SPI_1_PIN_AF;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* configure pins for their correct alternate function */
|
||||
for (int i = 0; i < 3; i++) {
|
||||
port->MODER &= ~(3 << (pin[i] * 2));
|
||||
port->MODER |= (2 << (pin[i] * 2));
|
||||
int hl = (pin[i] < 8) ? 0 : 1;
|
||||
port->AFR[hl] &= ~(0xf << ((pin[i] - (hl * 8)) * 4));
|
||||
port->AFR[hl] |= (af << ((pin[i] - (hl * 8)) * 4));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_transfer_byte(spi_t dev, char out, char *in)
|
||||
{
|
||||
char tmp;
|
||||
SPI_TypeDef *spi = 0;
|
||||
|
||||
switch (dev) {
|
||||
#if SPI_0_EN
|
||||
case SPI_0:
|
||||
spi = SPI_0_DEV;
|
||||
break;
|
||||
#endif
|
||||
#if SPI_1_EN
|
||||
case SPI_1:
|
||||
spi = SPI_1_DEV;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* wait for an eventually previous byte to be readily transferred */
|
||||
while(!(spi->SR & SPI_SR_TXE));
|
||||
/* put next byte into the output register */
|
||||
spi->DR = out;
|
||||
/* wait until the current byte was successfully transferred */
|
||||
while(!(spi->SR & SPI_SR_RXNE));
|
||||
/* read response byte to reset flags */
|
||||
tmp = spi->DR;
|
||||
/* 'return' response byte if wished for */
|
||||
if (in) {
|
||||
*in = tmp;
|
||||
}
|
||||
|
||||
#if ENABLE_DEBUG
|
||||
if (in != NULL) {
|
||||
DEBUG("\nout: %x in: %x \n", out, *in, transferred);
|
||||
}
|
||||
else {
|
||||
DEBUG("\nout: %x in: was nullPointer\n", out, transferred);
|
||||
}
|
||||
#endif /*ENABLE_DEBUG */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length)
|
||||
{
|
||||
char res;
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (out) {
|
||||
count += spi_transfer_byte(dev, out[i], &res);
|
||||
}
|
||||
else {
|
||||
count += spi_transfer_byte(dev, 0, &res);
|
||||
}
|
||||
if (in) {
|
||||
in[i] = res;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int spi_transfer_reg(spi_t dev, uint8_t reg, char out, char *in)
|
||||
{
|
||||
spi_transfer_byte(dev, reg, 0);
|
||||
return spi_transfer_byte(dev, out, in);
|
||||
}
|
||||
|
||||
int spi_transfer_regs(spi_t dev, uint8_t reg, char *out, char *in, unsigned int length)
|
||||
{
|
||||
spi_transfer_byte(dev, reg, 0);
|
||||
return spi_transfer_bytes(dev, out, in, length);
|
||||
}
|
||||
|
||||
void spi_transmission_begin(spi_t dev, char reset_val)
|
||||
{
|
||||
/* slave mode is not (yet) supported */
|
||||
}
|
||||
|
||||
void spi_poweron(spi_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if SPI_0_EN
|
||||
case SPI_0:
|
||||
SPI_0_CLKEN();
|
||||
break;
|
||||
#endif
|
||||
#if SPI_1_EN
|
||||
case SPI_1:
|
||||
SPI_1_CLKEN();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void spi_poweroff(spi_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if SPI_0_EN
|
||||
case SPI_0:
|
||||
while (SPI_0_DEV->SR & SPI_SR_BSY);
|
||||
SPI_0_CLKDIS();
|
||||
break;
|
||||
#endif
|
||||
#if SPI_1_EN
|
||||
case SPI_1:
|
||||
while (SPI_1_DEV->SR & SPI_SR_BSY);
|
||||
SPI_1_CLKDIS();
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SPI_NUMOF */
|
409
cpu/stm32l1/periph/timer.c
Normal file
409
cpu/stm32l1/periph/timer.c
Normal file
@ -0,0 +1,409 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup driver_periph
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level timer driver implementation
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "board.h"
|
||||
#include "periph_conf.h"
|
||||
#include "periph/timer.h"
|
||||
|
||||
#include "thread.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/* guard file in case no TIMER device is defined */
|
||||
#if TIMER_0_EN || TIMER_1_EN
|
||||
|
||||
static inline void irq_handler(tim_t timer, TIM_TypeDef *dev0, TIM_TypeDef *dev1);
|
||||
|
||||
typedef struct {
|
||||
void (*cb)(int);
|
||||
} timer_conf_t;
|
||||
|
||||
/**
|
||||
* Timer state memory
|
||||
*/
|
||||
static timer_conf_t config[TIMER_NUMOF];
|
||||
|
||||
int timer_init(tim_t dev, unsigned int ticks_per_us, void (*callback)(int))
|
||||
{
|
||||
TIM_TypeDef *timer0;
|
||||
TIM_TypeDef *timer1;
|
||||
uint8_t trigger_selector;
|
||||
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
/* enable timer peripheral clock */
|
||||
TIMER_0_CLKEN();
|
||||
/* set timer's IRQ priority */
|
||||
NVIC_SetPriority(TIMER_0_IRQ_CHAN_0, TIMER_0_IRQ_PRIO);
|
||||
NVIC_SetPriority(TIMER_0_IRQ_CHAN_1, TIMER_0_IRQ_PRIO);
|
||||
/* select timer */
|
||||
timer0 = TIMER_0_DEV_0;
|
||||
timer1 = TIMER_0_DEV_1;
|
||||
trigger_selector = TIMER_0_TRIG_SEL;
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_1_EN
|
||||
case TIMER_1:
|
||||
/* enable timer peripheral clock */
|
||||
TIMER_1_CLKEN();
|
||||
/* set timer's IRQ priority */
|
||||
NVIC_SetPriority(TIMER_1_IRQ_CHAN_0, TIMER_1_IRQ_PRIO);
|
||||
NVIC_SetPriority(TIMER_1_IRQ_CHAN_1, TIMER_1_IRQ_PRIO);
|
||||
/* select timer */
|
||||
timer0 = TIMER_1_DEV_0;
|
||||
timer1 = TIMER_1_DEV_1;
|
||||
trigger_selector = TIMER_1_TRIG_SEL;
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* set callback function */
|
||||
config[dev].cb = callback;
|
||||
|
||||
/* set timer to run in counter mode */
|
||||
timer0->CR1 = (TIM_CR1_ARPE | TIM_CR1_URS);
|
||||
timer1->CR1 = TIM_CR1_URS;
|
||||
|
||||
/* configure master timer0 */
|
||||
/* send update event as trigger output */
|
||||
timer0->CR2 |= TIM_CR2_MMS_1;
|
||||
/* set auto-reload and prescaler values and load new values */
|
||||
timer0->ARR = TIMER_0_MAX_VALUE;
|
||||
timer0->PSC = TIMER_0_PRESCALER * ticks_per_us;
|
||||
|
||||
/* configure slave timer1 */
|
||||
/* get input trigger */
|
||||
timer1->SMCR |= trigger_selector;
|
||||
/* external clock mode 1 */
|
||||
timer1->SMCR |= TIM_SMCR_SMS;
|
||||
|
||||
/* enable the timer's interrupt */
|
||||
timer_irq_enable(dev);
|
||||
|
||||
/* start the timer */
|
||||
timer_start(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_set(tim_t dev, int channel, unsigned int timeout)
|
||||
{
|
||||
int now = timer_read(dev);
|
||||
return timer_set_absolute(dev, channel, now + timeout - 1);
|
||||
}
|
||||
|
||||
int timer_set_absolute(tim_t dev, int channel, unsigned int value)
|
||||
{
|
||||
TIM_TypeDef *timer0;
|
||||
TIM_TypeDef *timer1;
|
||||
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
/* select timer */
|
||||
timer0 = TIMER_0_DEV_0;
|
||||
timer1 = TIMER_0_DEV_1;
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_1_EN
|
||||
case TIMER_1:
|
||||
/* select timer */
|
||||
timer0 = TIMER_1_DEV_0;
|
||||
timer1 = TIMER_1_DEV_1;
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
timer0->DIER &= ~TIM_DIER_UIE;
|
||||
|
||||
switch (channel) {
|
||||
case 0:
|
||||
timer0->CCR1 = (0xffff & value);
|
||||
timer1->CCR1 = (value >> 16);
|
||||
timer0->SR &= ~TIM_SR_CC1IF;
|
||||
timer0->DIER |= TIM_DIER_CC1IE;
|
||||
DEBUG("Channel 1 set to %x\n", value);
|
||||
break;
|
||||
case 1:
|
||||
timer0->CCR2 = (0xffff & value);
|
||||
timer1->CCR2 = (value >> 16);
|
||||
timer0->SR &= ~TIM_SR_CC2IF;
|
||||
timer0->DIER |= TIM_DIER_CC2IE;
|
||||
DEBUG("Channel 2 set to %x\n", value);
|
||||
break;
|
||||
case 2:
|
||||
timer0->CCR3 = (0xffff & value);
|
||||
timer1->CCR3 = (value >> 16);
|
||||
timer0->SR &= ~TIM_SR_CC3IF;
|
||||
timer0->DIER |= TIM_DIER_CC3IE;
|
||||
DEBUG("Channel 3 set to %x\n", value);
|
||||
break;
|
||||
case 3:
|
||||
timer0->CCR4 = (0xffff & value);
|
||||
timer1->CCR4 = (value >> 16);
|
||||
timer0->SR &= ~TIM_SR_CC4IF;
|
||||
timer0->DIER |= TIM_DIER_CC4IE;
|
||||
DEBUG("Channel 4 set to %x\n", value);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_clear(tim_t dev, int channel)
|
||||
{
|
||||
TIM_TypeDef *timer0;
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
timer0 = TIMER_0_DEV_0;
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_1_EN
|
||||
case TIMER_1:
|
||||
timer0 = TIMER_1_DEV_0;
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
switch (channel) {
|
||||
case 0:
|
||||
timer0->DIER &= ~TIM_DIER_CC1IE;
|
||||
break;
|
||||
case 1:
|
||||
timer0->DIER &= ~TIM_DIER_CC2IE;
|
||||
break;
|
||||
case 2:
|
||||
timer0->DIER &= ~TIM_DIER_CC3IE;
|
||||
break;
|
||||
case 3:
|
||||
timer0->DIER &= ~TIM_DIER_CC4IE;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int timer_read(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
return (((unsigned int)(0xffff & TIMER_0_DEV_0->CNT)) | (TIMER_0_DEV_1->CNT<<16));
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_1_EN
|
||||
case TIMER_1:
|
||||
return (((unsigned int)(0xffff & TIMER_1_DEV_0->CNT)) | (TIMER_1_DEV_1->CNT<<16));
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void timer_start(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
/* slave has to be enabled first */
|
||||
TIMER_0_DEV_1->CR1 |= TIM_CR1_CEN;
|
||||
TIMER_0_DEV_0->CR1 |= TIM_CR1_CEN;
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_1_EN
|
||||
case TIMER_1:
|
||||
/* slave has to be enabled first */
|
||||
TIMER_1_DEV_1->CR1 |= TIM_CR1_CEN;
|
||||
TIMER_1_DEV_0->CR1 |= TIM_CR1_CEN;
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void timer_stop(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
TIMER_0_DEV_0->CR1 &= ~TIM_CR1_CEN;
|
||||
TIMER_0_DEV_1->CR1 &= ~TIM_CR1_CEN;
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_1_EN
|
||||
case TIMER_1:
|
||||
TIMER_1_DEV_0->CR1 &= ~TIM_CR1_CEN;
|
||||
TIMER_1_DEV_1->CR1 &= ~TIM_CR1_CEN;
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void timer_irq_enable(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
NVIC_EnableIRQ(TIMER_0_IRQ_CHAN_0);
|
||||
NVIC_EnableIRQ(TIMER_0_IRQ_CHAN_1);
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_1_EN
|
||||
case TIMER_1:
|
||||
NVIC_EnableIRQ(TIMER_1_IRQ_CHAN_0);
|
||||
NVIC_EnableIRQ(TIMER_1_IRQ_CHAN_1);
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void timer_irq_disable(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
NVIC_DisableIRQ(TIMER_0_IRQ_CHAN_0);
|
||||
NVIC_DisableIRQ(TIMER_0_IRQ_CHAN_1);
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_1_EN
|
||||
case TIMER_1:
|
||||
NVIC_DisableIRQ(TIMER_1_IRQ_CHAN_0);
|
||||
NVIC_DisableIRQ(TIMER_1_IRQ_CHAN_1);
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void timer_reset(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
TIMER_0_DEV_0->CNT = 0;
|
||||
TIMER_0_DEV_1->CNT = 0;
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_1_EN
|
||||
case TIMER_1:
|
||||
TIMER_1_DEV_0->CNT = 0;
|
||||
TIMER_1_DEV_1->CNT = 0;
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if TIMER_0_EN
|
||||
void TIMER_0_ISR_0(void)
|
||||
{
|
||||
DEBUG("\nenter ISR\n");
|
||||
irq_handler(TIMER_0, TIMER_0_DEV_0, TIMER_0_DEV_1);
|
||||
DEBUG("leave ISR\n\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TIMER_1_EN
|
||||
void TIMER_1_ISR_0(void)
|
||||
{
|
||||
irq_handler(TIMER_0, TIMER_1_DEV_0, TIMER_1_DEV_1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void irq_handler(tim_t timer, TIM_TypeDef *dev0, TIM_TypeDef *dev1)
|
||||
{
|
||||
DEBUG("CNT: %08x SR/DIER: %08x\n", ((dev1->CNT<<16) | (0xffff & dev0->CNT)),
|
||||
((dev0->SR<<16) | (0xffff & dev0->DIER)));
|
||||
|
||||
if ((dev0->SR & TIM_SR_CC1IF) && (dev0->DIER & TIM_DIER_CC1IE)) {
|
||||
/* clear interrupt anyway */
|
||||
dev0->SR &= ~TIM_SR_CC1IF;
|
||||
/* if higher 16bit also match */
|
||||
if (dev1->CNT >= dev1->CCR1) {
|
||||
dev0->DIER &= ~TIM_DIER_CC1IE;
|
||||
config[timer].cb(0);
|
||||
}
|
||||
DEBUG("channel 1 CCR: %08x\n", ((dev1->CCR1<<16) | (0xffff & dev0->CCR1)));
|
||||
}
|
||||
else if ((dev0->SR & TIM_SR_CC2IF) && (dev0->DIER & TIM_DIER_CC2IE)) {
|
||||
/* clear interrupt anyway */
|
||||
dev0->SR &= ~TIM_SR_CC2IF;
|
||||
/* if higher 16bit also match */
|
||||
if (dev1->CNT >= dev1->CCR2) {
|
||||
dev0->DIER &= ~TIM_DIER_CC2IE;
|
||||
config[timer].cb(1);
|
||||
}
|
||||
DEBUG("channel 2 CCR: %08x\n", ((dev1->CCR2<<16) | (0xffff & dev0->CCR2)));
|
||||
}
|
||||
else if ((dev0->SR & TIM_SR_CC3IF) && (dev0->DIER & TIM_DIER_CC3IE)) {
|
||||
/* clear interrupt anyway */
|
||||
dev0->SR &= ~TIM_SR_CC3IF;
|
||||
/* if higher 16bit also match */
|
||||
if (dev1->CNT >= dev1->CCR3) {
|
||||
dev0->DIER &= ~TIM_DIER_CC3IE;
|
||||
config[timer].cb(2);
|
||||
}
|
||||
DEBUG("channel 3 CCR: %08x\n", ((dev1->CCR3<<16) | (0xffff & dev0->CCR3)));
|
||||
}
|
||||
else if ((dev0->SR & TIM_SR_CC4IF) && (dev0->DIER & TIM_DIER_CC4IE)) {
|
||||
/* clear interrupt anyway */
|
||||
dev0->SR &= ~TIM_SR_CC4IF;
|
||||
/* if higher 16bit also match */
|
||||
if (dev1->CNT >= dev1->CCR4) {
|
||||
dev0->DIER &= ~TIM_DIER_CC4IE;
|
||||
config[timer].cb(3);
|
||||
}
|
||||
DEBUG("channel 4 CCR: %08x\n", ((dev1->CCR4<<16) | (0xffff & dev0->CCR4)));
|
||||
}
|
||||
else {
|
||||
dev0->SR = 0;
|
||||
}
|
||||
if (sched_context_switch_request) {
|
||||
thread_yield();
|
||||
}
|
||||
}
|
||||
#endif /* TIMER_0_EN || TIMER_1_EN */
|
328
cpu/stm32l1/periph/uart.c
Normal file
328
cpu/stm32l1/periph/uart.c
Normal file
@ -0,0 +1,328 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup driver_periph
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level UART driver implementation
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "cpu.h"
|
||||
#include "sched.h"
|
||||
#include "thread.h"
|
||||
#include "periph_conf.h"
|
||||
#include "periph/uart.h"
|
||||
|
||||
/* guard file in case no UART device was specified */
|
||||
#if UART_NUMOF
|
||||
|
||||
/**
|
||||
* @brief Each UART device has to store two callbacks.
|
||||
*/
|
||||
typedef struct {
|
||||
uart_rx_cb_t rx_cb;
|
||||
uart_tx_cb_t tx_cb;
|
||||
void *arg;
|
||||
} uart_conf_t;
|
||||
|
||||
/**
|
||||
* @brief Unified interrupt handler for all UART devices
|
||||
*
|
||||
* @param uartnum the number of the UART that triggered the ISR
|
||||
* @param uart the UART device that triggered the ISR
|
||||
*/
|
||||
static inline void irq_handler(uart_t uartnum, USART_TypeDef *uart);
|
||||
|
||||
/**
|
||||
* @brief Allocate memory to store the callback functions.
|
||||
*/
|
||||
static uart_conf_t uart_config[UART_NUMOF];
|
||||
|
||||
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, uart_tx_cb_t tx_cb, void *arg)
|
||||
{
|
||||
/* do basic initialization */
|
||||
int res = uart_init_blocking(uart, baudrate);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/* remember callback addresses */
|
||||
uart_config[uart].rx_cb = rx_cb;
|
||||
uart_config[uart].tx_cb = tx_cb;
|
||||
uart_config[uart].arg = arg;
|
||||
|
||||
|
||||
/* enable receive interrupt */
|
||||
switch (uart) {
|
||||
#if UART_0_EN
|
||||
case UART_0:
|
||||
NVIC_SetPriority(UART_0_IRQ, UART_IRQ_PRIO);
|
||||
NVIC_EnableIRQ(UART_0_IRQ);
|
||||
UART_0_DEV->CR1 |= USART_CR1_RXNEIE;
|
||||
break;
|
||||
#endif
|
||||
#if UART_1_EN
|
||||
case UART_1:
|
||||
NVIC_SetPriority(UART_1_IRQ, UART_IRQ_PRIO);
|
||||
NVIC_EnableIRQ(UART_1_IRQ);
|
||||
UART_1_DEV->CR1 |= USART_CR1_RXNEIE;
|
||||
break;
|
||||
#endif
|
||||
#if UART_2_EN
|
||||
case UART_2:
|
||||
NVIC_SetPriority(UART_2_IRQ, UART_IRQ_PRIO);
|
||||
NVIC_EnableIRQ(UART_2_IRQ);
|
||||
UART_2_DEV->CR1 |= USART_CR1_RXNEIE;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uart_init_blocking(uart_t uart, uint32_t baudrate)
|
||||
{
|
||||
USART_TypeDef *dev = 0;
|
||||
GPIO_TypeDef *port = 0;
|
||||
uint32_t tx_pin = 0;
|
||||
uint32_t rx_pin = 0;
|
||||
uint8_t af = 0;
|
||||
float clk = 0;
|
||||
float divider;
|
||||
uint16_t mantissa;
|
||||
uint8_t fraction;
|
||||
|
||||
switch (uart) {
|
||||
#if UART_0_EN
|
||||
case UART_0:
|
||||
dev = UART_0_DEV;
|
||||
port = UART_0_PORT;
|
||||
clk = UART_0_CLK;
|
||||
tx_pin = UART_0_TX_PIN;
|
||||
rx_pin = UART_0_RX_PIN;
|
||||
af = UART_0_AF;
|
||||
UART_0_CLKEN();
|
||||
UART_0_PORT_CLKEN();
|
||||
break;
|
||||
#endif
|
||||
#if UART_1_EN
|
||||
case UART_1:
|
||||
dev = UART_1_DEV;
|
||||
port = UART_1_PORT;
|
||||
clk = UART_1_CLK;
|
||||
tx_pin = UART_1_TX_PIN;
|
||||
rx_pin = UART_1_RX_PIN;
|
||||
af = UART_1_AF;
|
||||
UART_1_CLKEN();
|
||||
UART_1_PORT_CLKEN();
|
||||
break;
|
||||
#endif
|
||||
#if UART_2_EN
|
||||
case UART_2:
|
||||
dev = UART_2_DEV;
|
||||
port = UART_2_PORT;
|
||||
clk = UART_2_CLK;
|
||||
tx_pin = UART_2_TX_PIN;
|
||||
rx_pin = UART_2_RX_PIN;
|
||||
af = UART_2_AF;
|
||||
UART_2_CLKEN();
|
||||
UART_2_PORT_CLKEN();
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* uart_configure RX and TX pins, set pin to use alternative function mode */
|
||||
port->MODER &= ~(3 << (rx_pin * 2) | 3 << (tx_pin * 2));
|
||||
port->MODER |= 2 << (rx_pin * 2) | 2 << (tx_pin * 2);
|
||||
/* and assign alternative function */
|
||||
if (rx_pin < 8) {
|
||||
port->AFR[0] &= ~(0xf << (rx_pin * 4));
|
||||
port->AFR[0] |= af << (rx_pin * 4);
|
||||
}
|
||||
else {
|
||||
port->AFR[1] &= ~(0xf << ((rx_pin - 8) * 4));
|
||||
port->AFR[1] |= af << ((rx_pin - 8) * 4);
|
||||
}
|
||||
if (tx_pin < 8) {
|
||||
port->AFR[0] &= ~(0xf << (tx_pin * 4));
|
||||
port->AFR[0] |= af << (tx_pin * 4);
|
||||
}
|
||||
else {
|
||||
port->AFR[1] &= ~(0xf << ((tx_pin - 8) * 4));
|
||||
port->AFR[1] |= af << ((tx_pin - 8) * 4);
|
||||
}
|
||||
|
||||
/* uart_configure UART to mode 8N1 with given baudrate */
|
||||
divider = clk / (16 * baudrate);
|
||||
mantissa = (uint16_t)divider;
|
||||
fraction = (uint8_t)((divider - mantissa) * 16);
|
||||
dev->BRR = ((mantissa & 0x0fff) << 4) | (0x0f & fraction);
|
||||
|
||||
/* enable receive and transmit mode */
|
||||
dev->CR3 = 0;
|
||||
dev->CR2 = 0;
|
||||
dev->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uart_tx_begin(uart_t uart)
|
||||
{
|
||||
switch (uart) {
|
||||
#if UART_0_EN
|
||||
case UART_0:
|
||||
UART_0_DEV->CR1 |= USART_CR1_TXEIE;
|
||||
break;
|
||||
#endif
|
||||
#if UART_1_EN
|
||||
case UART_1:
|
||||
UART_1_DEV->CR1 |= USART_CR1_TXEIE;
|
||||
break;
|
||||
#endif
|
||||
#if UART_2_EN
|
||||
case UART_2:
|
||||
UART_2_DEV->CR1 |= USART_CR1_TXEIE;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int uart_write(uart_t uart, char data)
|
||||
{
|
||||
USART_TypeDef *dev = 0;
|
||||
|
||||
switch (uart) {
|
||||
#if UART_0_EN
|
||||
case UART_0:
|
||||
dev = UART_0_DEV;
|
||||
break;
|
||||
#endif
|
||||
#if UART_1_EN
|
||||
case UART_1:
|
||||
dev = UART_1_DEV;
|
||||
break;
|
||||
#endif
|
||||
#if UART_2_EN
|
||||
case UART_2:
|
||||
dev = UART_2_DEV;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dev->SR & USART_SR_TXE) {
|
||||
dev->DR = (uint8_t)data;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uart_read_blocking(uart_t uart, char *data)
|
||||
{
|
||||
USART_TypeDef *dev = 0;
|
||||
|
||||
switch (uart) {
|
||||
#if UART_0_EN
|
||||
case UART_0:
|
||||
dev = UART_0_DEV;
|
||||
break;
|
||||
#endif
|
||||
#if UART_1_EN
|
||||
case UART_1:
|
||||
dev = UART_1_DEV;
|
||||
break;
|
||||
#endif
|
||||
#if UART_2_EN
|
||||
case UART_2:
|
||||
dev = UART_2_DEV;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
while (!(dev->SR & USART_SR_RXNE));
|
||||
*data = (char)dev->DR;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uart_write_blocking(uart_t uart, char data)
|
||||
{
|
||||
USART_TypeDef *dev = 0;
|
||||
|
||||
switch (uart) {
|
||||
#if UART_0_EN
|
||||
case UART_0:
|
||||
dev = UART_0_DEV;
|
||||
break;
|
||||
#endif
|
||||
#if UART_1_EN
|
||||
case UART_1:
|
||||
dev = UART_1_DEV;
|
||||
break;
|
||||
#endif
|
||||
#if UART_2_EN
|
||||
case UART_2:
|
||||
dev = UART_2_DEV;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
while (!(dev->SR & USART_SR_TXE));
|
||||
dev->DR = (uint8_t)data;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if UART_0_EN
|
||||
void UART_0_ISR(void)
|
||||
{
|
||||
irq_handler(UART_0, UART_0_DEV);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UART_1_EN
|
||||
void UART_1_ISR(void)
|
||||
{
|
||||
irq_handler(UART_1, UART_1_DEV);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UART_2_EN
|
||||
void UART_2_ISR(void)
|
||||
{
|
||||
irq_handler(UART_2, UART_2_DEV);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void irq_handler(uint8_t uartnum, USART_TypeDef *dev)
|
||||
{
|
||||
if (dev->SR & USART_SR_RXNE) {
|
||||
char data = (char)dev->DR;
|
||||
uart_config[uartnum].rx_cb(uart_config[uartnum].arg, data);
|
||||
}
|
||||
else if (dev->SR & USART_SR_TXE) {
|
||||
if (uart_config[uartnum].tx_cb(uart_config[uartnum].arg) == 0) {
|
||||
dev->CR1 &= ~(USART_CR1_TXEIE);
|
||||
}
|
||||
}
|
||||
if (sched_context_switch_request) {
|
||||
thread_yield();
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* UART_NUMOF */
|
266
cpu/stm32l1/startup.c
Normal file
266
cpu/stm32l1/startup.c
Normal file
@ -0,0 +1,266 @@
|
||||
/*
|
||||
* 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_stm32l1
|
||||
* @{
|
||||
*
|
||||
* @file startup.c
|
||||
* @brief Startup code and interrupt vector definition
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "crash.h"
|
||||
|
||||
|
||||
/**
|
||||
* memory markers as defined in the linker script
|
||||
*/
|
||||
extern uint32_t _sfixed;
|
||||
extern uint32_t _efixed;
|
||||
extern uint32_t _etext;
|
||||
extern uint32_t _srelocate;
|
||||
extern uint32_t _erelocate;
|
||||
extern uint32_t _szero;
|
||||
extern uint32_t _ezero;
|
||||
extern uint32_t _sstack;
|
||||
extern uint32_t _estack;
|
||||
|
||||
|
||||
/**
|
||||
* @brief functions for initializing the board, std-lib and kernel
|
||||
*/
|
||||
extern void board_init(void);
|
||||
extern void kernel_init(void);
|
||||
extern void __libc_init_array(void);
|
||||
|
||||
/**
|
||||
* @brief This function is the entry point after a system reset
|
||||
*
|
||||
* After a system reset, the following steps are necessary and carried out:
|
||||
* 1. load data section from flash to ram
|
||||
* 2. overwrite uninitialized data section (BSS) with zeros
|
||||
* 3. initialize the newlib
|
||||
* 4. initialize the board (sync clock, setup std-IO)
|
||||
* 5. initialize and start RIOTs kernel
|
||||
*/
|
||||
void reset_handler(void)
|
||||
{
|
||||
uint32_t *dst;
|
||||
uint32_t *src = &_etext;
|
||||
|
||||
/* load data section from flash to ram */
|
||||
for (dst = &_srelocate; dst < &_erelocate; ) {
|
||||
*(dst++) = *(src++);
|
||||
}
|
||||
|
||||
/* default bss section to zero */
|
||||
for (dst = &_szero; dst < &_ezero; ) {
|
||||
*(dst++) = 0;
|
||||
}
|
||||
|
||||
/* initialize the board and startup the kernel */
|
||||
board_init();
|
||||
/* initialize std-c library (this should be done after board_init) */
|
||||
__libc_init_array();
|
||||
/* startup the kernel */
|
||||
kernel_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Default handler is called in case no interrupt handler was defined
|
||||
*/
|
||||
void dummy_handler(void)
|
||||
{
|
||||
core_panic(DUMMY_HANDLER, "DUMMY HANDLER");
|
||||
while (1) {asm ("nop");}
|
||||
}
|
||||
|
||||
void isr_nmi(void)
|
||||
{
|
||||
while (1) {asm ("nop");}
|
||||
}
|
||||
|
||||
void isr_mem_manage(void)
|
||||
{
|
||||
while (1) {asm ("nop");}
|
||||
}
|
||||
|
||||
void isr_debug_mon(void)
|
||||
{
|
||||
while (1) {asm ("nop");}
|
||||
}
|
||||
|
||||
void isr_hard_fault(void)
|
||||
{
|
||||
core_panic(HARD_FAULT, "HARD FAULT");
|
||||
while (1) {asm ("nop");}
|
||||
}
|
||||
|
||||
void isr_bus_fault(void)
|
||||
{
|
||||
core_panic(BUS_FAULT, "BUS FAULT");
|
||||
while (1) {asm ("nop");}
|
||||
}
|
||||
|
||||
void isr_usage_fault(void)
|
||||
{
|
||||
core_panic(USAGE_FAULT, "USAGE FAULT");
|
||||
while (1) {asm ("nop");}
|
||||
}
|
||||
|
||||
/* Cortex-M specific interrupt vectors */
|
||||
void isr_svc(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_pendsv(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_systick(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
|
||||
/* stm32f1 specific interrupt vector */
|
||||
void isr_wwdg(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_pvd(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_tamper_stamp(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_rtc_wkup(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_flash(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_rcc(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_exti0(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_exti1(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_exti2(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_exti3(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_exti4(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_dma1_ch1(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_dma1_ch2(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_dma1_ch3(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_dma1_ch4(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_dma1_ch5(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_dma1_ch6(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_dma1_ch7(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_adc1(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_usb_hp(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_usb_lp(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_dac(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_comp(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_exti9_5(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_lcd(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_tim9(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_tim10(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_tim11(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_tim2(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_tim3(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_tim4(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_i2c1_ev(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_i2c1_er(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_i2c2_ev(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_i2c2_er(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_spi1(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_spi2(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_usart1(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_usart2(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_usart3(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_exti15_10(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_rtc_alarm(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_usb_fs_wkup(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_tim6(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_tim7(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_sdio(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_tim5(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_spi3(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_uart4(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_uart5(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_dma2_ch1(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_dma2_ch2(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_dma2_ch3(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_dma2_ch4(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_dma2_ch5(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_aes(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
void isr_comp_acq(void) __attribute__ ((weak, alias("dummy_handler")));
|
||||
|
||||
|
||||
/* interrupt vector table */
|
||||
__attribute__ ((section(".vectors")))
|
||||
const void *interrupt_vector[] = {
|
||||
/* Stack pointer */
|
||||
(void*) (&_estack), /* pointer to the top of the empty stack */
|
||||
/* Cortex-M handlers */
|
||||
(void*) reset_handler, /* entry point of the program */
|
||||
(void*) isr_nmi, /* non maskable interrupt handler */
|
||||
(void*) isr_hard_fault, /* if you end up here its not good */
|
||||
(void*) isr_mem_manage, /* memory controller interrupt */
|
||||
(void*) isr_bus_fault, /* also not good to end up here */
|
||||
(void*) isr_usage_fault, /* autsch */
|
||||
(void*) (0UL), /* Reserved */
|
||||
(void*) (0UL), /* Reserved */
|
||||
(void*) (0UL), /* Reserved */
|
||||
(void*) (0UL), /* Reserved */
|
||||
(void*) isr_svc, /* system call interrupt */
|
||||
(void*) isr_debug_mon, /* debug interrupt */
|
||||
(void*) (0UL), /* Reserved */
|
||||
(void*) isr_pendsv, /* pendSV interrupt, used for task switching in RIOT */
|
||||
(void*) isr_systick, /* SysTick interrupt, not used in RIOT */
|
||||
/* STM specific peripheral handlers */
|
||||
(void*) isr_wwdg,
|
||||
(void*) isr_pvd,
|
||||
(void*) isr_tamper_stamp,
|
||||
(void*) isr_rtc_wkup,
|
||||
(void*) isr_flash,
|
||||
(void*) isr_rcc,
|
||||
(void*) isr_exti0,
|
||||
(void*) isr_exti1,
|
||||
(void*) isr_exti2,
|
||||
(void*) isr_exti3,
|
||||
(void*) isr_exti4,
|
||||
(void*) isr_dma1_ch1,
|
||||
(void*) isr_dma1_ch2,
|
||||
(void*) isr_dma1_ch3,
|
||||
(void*) isr_dma1_ch4,
|
||||
(void*) isr_dma1_ch5,
|
||||
(void*) isr_dma1_ch6,
|
||||
(void*) isr_dma1_ch7,
|
||||
(void*) isr_adc1,
|
||||
(void*) isr_usb_hp,
|
||||
(void*) isr_usb_lp,
|
||||
(void*) isr_dac,
|
||||
(void*) isr_comp,
|
||||
(void*) isr_exti9_5,
|
||||
(void*) isr_lcd,
|
||||
(void*) isr_tim9,
|
||||
(void*) isr_tim10,
|
||||
(void*) isr_tim11,
|
||||
(void*) isr_tim2,
|
||||
(void*) isr_tim3,
|
||||
(void*) isr_tim4,
|
||||
(void*) isr_i2c1_ev,
|
||||
(void*) isr_i2c1_er,
|
||||
(void*) isr_i2c2_ev,
|
||||
(void*) isr_i2c2_er,
|
||||
(void*) isr_spi1,
|
||||
(void*) isr_spi2,
|
||||
(void*) isr_usart1,
|
||||
(void*) isr_usart2,
|
||||
(void*) isr_usart3,
|
||||
(void*) isr_exti15_10,
|
||||
(void*) isr_rtc_alarm,
|
||||
(void*) isr_usb_fs_wkup,
|
||||
(void*) isr_tim6,
|
||||
(void*) isr_tim7,
|
||||
(void*) isr_sdio,
|
||||
(void*) isr_tim5,
|
||||
(void*) isr_spi3,
|
||||
(void*) isr_uart4,
|
||||
(void*) isr_uart5,
|
||||
(void*) isr_dma2_ch1,
|
||||
(void*) isr_dma2_ch2,
|
||||
(void*) isr_dma2_ch3,
|
||||
(void*) isr_dma2_ch4,
|
||||
(void*) isr_dma2_ch5,
|
||||
(void*) isr_aes,
|
||||
(void*) isr_comp_acq,
|
||||
};
|
144
cpu/stm32l1/stm32l152ret6_linkerscript.ld
Normal file
144
cpu/stm32l1/stm32l152ret6_linkerscript.ld
Normal file
@ -0,0 +1,144 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* SAM Software Package License
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2012, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following condition is met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
SEARCH_DIR(.)*/
|
||||
|
||||
/* Memory Spaces Definitions */
|
||||
MEMORY
|
||||
{
|
||||
rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K
|
||||
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 80K
|
||||
}
|
||||
|
||||
/* The stack size used by the application. NOTE: you need to adjust */
|
||||
STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : 0x200 ;
|
||||
|
||||
/* Section Definitions */
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sfixed = .;
|
||||
KEEP(*(.vectors .vectors.*))
|
||||
*(.text .text.* .gnu.linkonce.t.*)
|
||||
*(.glue_7t) *(.glue_7)
|
||||
*(.rodata .rodata* .gnu.linkonce.r.*)
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
|
||||
/* Support C constructors, and C destructors in both user code
|
||||
and the C library. This also provides support for C++ code. */
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.init))
|
||||
. = ALIGN(4);
|
||||
__preinit_array_start = .;
|
||||
KEEP (*(.preinit_array))
|
||||
__preinit_array_end = .;
|
||||
|
||||
. = ALIGN(4);
|
||||
__init_array_start = .;
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
__init_array_end = .;
|
||||
|
||||
. = ALIGN(0x4);
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*crtend.o(.ctors))
|
||||
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.fini))
|
||||
|
||||
. = ALIGN(4);
|
||||
__fini_array_start = .;
|
||||
KEEP (*(.fini_array))
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
__fini_array_end = .;
|
||||
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*crtend.o(.dtors))
|
||||
|
||||
. = ALIGN(4);
|
||||
_efixed = .; /* End of text section */
|
||||
} > rom
|
||||
|
||||
/* .ARM.exidx is sorted, so has to go in its own output section. */
|
||||
PROVIDE_HIDDEN (__exidx_start = .);
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} > rom
|
||||
PROVIDE_HIDDEN (__exidx_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
_etext = .;
|
||||
|
||||
.relocate : AT (_etext)
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_srelocate = .;
|
||||
*(.ramfunc .ramfunc.*);
|
||||
*(.data .data.*);
|
||||
. = ALIGN(4);
|
||||
_erelocate = .;
|
||||
} > ram
|
||||
|
||||
/* .bss section which is used for uninitialized data */
|
||||
.bss (NOLOAD) :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sbss = . ;
|
||||
_szero = .;
|
||||
*(.bss .bss.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_ebss = . ;
|
||||
_ezero = .;
|
||||
} > ram
|
||||
|
||||
/* stack section */
|
||||
.stack (NOLOAD) :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sstack = .;
|
||||
. = . + STACK_SIZE;
|
||||
. = ALIGN(4);
|
||||
_estack = .;
|
||||
} > ram
|
||||
|
||||
/* heap section */
|
||||
. = ALIGN(4);
|
||||
_sheap = . ;
|
||||
_eheap = ORIGIN(ram) + LENGTH(ram);
|
||||
}
|
347
cpu/stm32l1/syscalls.c
Normal file
347
cpu/stm32l1/syscalls.c
Normal file
@ -0,0 +1,347 @@
|
||||
/*
|
||||
* 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_stm32l1
|
||||
* @{
|
||||
*
|
||||
* @file syscalls.c
|
||||
* @brief NewLib system calls implementations for stm32l1
|
||||
*
|
||||
* @author Michael Baar <michael.baar@fu-berlin.de>
|
||||
* @author Stefan Pfeiffer <pfeiffer@inf.fu-berlin.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "thread.h"
|
||||
#include "kernel.h"
|
||||
#include "mutex.h"
|
||||
#include "ringbuffer.h"
|
||||
#include "irq.h"
|
||||
#include "periph/uart.h"
|
||||
|
||||
#ifdef MODULE_UART0
|
||||
#include "board_uart0.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* manage the heap
|
||||
*/
|
||||
extern char _sheap; /* start of the heap */
|
||||
extern char _eheap; /* end of the heap */
|
||||
caddr_t heap_top = (caddr_t)&_sheap + 4;
|
||||
|
||||
#ifndef MODULE_UART0
|
||||
/**
|
||||
* @brief use mutex for waiting on incoming UART chars
|
||||
*/
|
||||
static mutex_t uart_rx_mutex;
|
||||
static char rx_buf_mem[STDIO_RX_BUFSIZE];
|
||||
static ringbuffer_t rx_buf;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Receive a new character from the UART and put it into the receive buffer
|
||||
*/
|
||||
void rx_cb(void *arg, char data)
|
||||
{
|
||||
#ifndef MODULE_UART0
|
||||
(void)arg;
|
||||
|
||||
ringbuffer_add_one(&rx_buf, data);
|
||||
mutex_unlock(&uart_rx_mutex);
|
||||
#else
|
||||
if (uart0_handler_pid) {
|
||||
uart0_handle_incoming(data);
|
||||
|
||||
uart0_notify_thread();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize NewLib, called by __libc_init_array() from the startup script
|
||||
*/
|
||||
void _init(void)
|
||||
{
|
||||
#ifndef MODULE_UART0
|
||||
mutex_init(&uart_rx_mutex);
|
||||
ringbuffer_init(&rx_buf, rx_buf_mem, STDIO_RX_BUFSIZE);
|
||||
#endif
|
||||
uart_init(STDIO, STDIO_BAUDRATE, rx_cb, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free resources on NewLib de-initialization, not used for RIOT
|
||||
*/
|
||||
void _fini(void)
|
||||
{
|
||||
/* nothing to do here */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exit a program without cleaning up files
|
||||
*
|
||||
* If your system doesn't provide this, it is best to avoid linking with subroutines that
|
||||
* require it (exit, system).
|
||||
*
|
||||
* @param n the exit code, 0 for all OK, >0 for not OK
|
||||
*/
|
||||
void _exit(int n)
|
||||
{
|
||||
printf("#! exit %i: resetting\n", n);
|
||||
NVIC_SystemReset();
|
||||
while(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate memory from the heap.
|
||||
*
|
||||
* The current heap implementation is very rudimentary, it is only able to allocate
|
||||
* memory. But it does not
|
||||
* - check if the returned address is valid (no check if the memory very exists)
|
||||
* - have any means to free memory again
|
||||
*
|
||||
* TODO: check if the requested memory is really available
|
||||
*
|
||||
* @return [description]
|
||||
*/
|
||||
caddr_t _sbrk_r(struct _reent *r, ptrdiff_t incr)
|
||||
{
|
||||
unsigned int state = disableIRQ();
|
||||
caddr_t res = heap_top;
|
||||
|
||||
if (((incr > 0) && ((heap_top + incr > &_eheap) || (heap_top + incr < res))) ||
|
||||
((incr < 0) && ((heap_top + incr < &_sheap) || (heap_top + incr > res)))) {
|
||||
r->_errno = ENOMEM;
|
||||
res = (void *) -1;
|
||||
}
|
||||
else {
|
||||
heap_top += incr;
|
||||
}
|
||||
|
||||
restoreIRQ(state);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the process-ID of the current thread
|
||||
*
|
||||
* @return the process ID of the current thread
|
||||
*/
|
||||
int _getpid(void)
|
||||
{
|
||||
return sched_active_thread->pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send a signal to a given thread
|
||||
*
|
||||
* @param r TODO
|
||||
* @param pid TODO
|
||||
* @param sig TODO
|
||||
*
|
||||
* @return TODO
|
||||
*/
|
||||
__attribute__ ((weak))
|
||||
int _kill_r(struct _reent *r, int pid, int sig)
|
||||
{
|
||||
r->_errno = ESRCH; /* not implemented yet */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send a signal to a given thread (non-reentrant syscall)
|
||||
*
|
||||
* @param r TODO
|
||||
* @param pid TODO
|
||||
* @param sig TODO
|
||||
*
|
||||
* @return TODO
|
||||
*/
|
||||
__attribute__ ((weak))
|
||||
int _kill(int pid, int sig)
|
||||
{
|
||||
errno = ESRCH; /* not implemented yet */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Open a file
|
||||
*
|
||||
* @param r TODO
|
||||
* @param name TODO
|
||||
* @param mode TODO
|
||||
*
|
||||
* @return TODO
|
||||
*/
|
||||
int _open_r(struct _reent *r, const char *name, int mode)
|
||||
{
|
||||
r->_errno = ENODEV; /* not implemented yet */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read from a file
|
||||
*
|
||||
* All input is read from UART_0. The function will block until a byte is actually read.
|
||||
*
|
||||
* Note: the read function does not buffer - data will be lost if the function is not
|
||||
* called fast enough.
|
||||
*
|
||||
* TODO: implement more sophisticated read call.
|
||||
*
|
||||
* @param r TODO
|
||||
* @param fd TODO
|
||||
* @param buffer TODO
|
||||
* @param int TODO
|
||||
*
|
||||
* @return TODO
|
||||
*/
|
||||
int _read_r(struct _reent *r, int fd, void *buffer, unsigned int count)
|
||||
{
|
||||
#ifndef MODULE_UART0
|
||||
while (rx_buf.avail == 0) {
|
||||
mutex_lock(&uart_rx_mutex);
|
||||
}
|
||||
return ringbuffer_get(&rx_buf, (char*)buffer, rx_buf.avail);
|
||||
#else
|
||||
char *res = (char*)buffer;
|
||||
res[0] = (char)uart0_readc();
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write characters to a file
|
||||
*
|
||||
* All output is currently directed to UART_0, independent of the given file descriptor.
|
||||
* The write call will further block until the byte is actually written to the UART.
|
||||
*
|
||||
* TODO: implement more sophisticated write call.
|
||||
*
|
||||
* @param r TODO
|
||||
* @param fd TODO
|
||||
* @param data TODO
|
||||
* @param int TODO
|
||||
*
|
||||
* @return TODO
|
||||
*/
|
||||
int _write_r(struct _reent *r, int fd, const void *data, unsigned int count)
|
||||
{
|
||||
char *c = (char*)data;
|
||||
for (int i = 0; i < count; i++) {
|
||||
uart_write_blocking(UART_0, c[i]);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Close a file
|
||||
*
|
||||
* @param r TODO
|
||||
* @param fd TODO
|
||||
*
|
||||
* @return TODO
|
||||
*/
|
||||
int _close_r(struct _reent *r, int fd)
|
||||
{
|
||||
r->_errno = ENODEV; /* not implemented yet */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set position in a file
|
||||
*
|
||||
* @param r TODO
|
||||
* @param fd TODO
|
||||
* @param pos TODO
|
||||
* @param dir TODO
|
||||
*
|
||||
* @return TODO
|
||||
*/
|
||||
_off_t _lseek_r(struct _reent *r, int fd, _off_t pos, int dir)
|
||||
{
|
||||
r->_errno = ENODEV; /* not implemented yet */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Status of an open file
|
||||
*
|
||||
* @param r TODO
|
||||
* @param fd TODO
|
||||
* @param stat TODO
|
||||
*
|
||||
* @return TODO
|
||||
*/
|
||||
int _fstat_r(struct _reent *r, int fd, struct stat * st)
|
||||
{
|
||||
r->_errno = ENODEV; /* not implemented yet */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Status of a file (by name)
|
||||
*
|
||||
* @param r TODO
|
||||
* @param name TODO
|
||||
* @param stat TODO
|
||||
*
|
||||
* @return TODO
|
||||
*/
|
||||
int _stat_r(struct _reent *r, char *name, struct stat *st)
|
||||
{
|
||||
r->_errno = ENODEV; /* not implemented yet */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Query whether output stream is a terminal
|
||||
*
|
||||
* @param r TODO
|
||||
* @param fd TODO
|
||||
*
|
||||
* @return TODO
|
||||
*/
|
||||
int _isatty_r(struct _reent *r, int fd)
|
||||
{
|
||||
r->_errno = 0;
|
||||
if(fd == STDOUT_FILENO || fd == STDERR_FILENO) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove a file's directory entry
|
||||
*
|
||||
* @param r TODO
|
||||
* @param path TODO
|
||||
*
|
||||
* @return TODO
|
||||
*/
|
||||
int _unlink_r(struct _reent *r, char* path)
|
||||
{
|
||||
r->_errno = ENODEV; /* not implemented yet */
|
||||
return -1;
|
||||
}
|
1
dist/tools/licenses/patterns/mcd-st-liberty
vendored
Normal file
1
dist/tools/licenses/patterns/mcd-st-liberty
vendored
Normal file
@ -0,0 +1 @@
|
||||
Licensed under MCD-ST Liberty SW License Agreement V2, \(the "License"\); You may not use this file except in compliance with the License\. You may obtain a copy of the License at: http: www\.st\.com software_license_agreement_liberty_v2 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\. See the License for the specific language governing permissions and limitations under the License\.
|
@ -825,6 +825,7 @@ EXCLUDE_PATTERNS = */board/*/tools/* \
|
||||
*/boards/*/include/periph_conf.h \
|
||||
*/cpu/x86/include/x86_pci.h \
|
||||
*/cpu/sam3x8e/include/sam3x8e.h \
|
||||
*/cpu/stm32l1/include/stm32l1xx.h \
|
||||
|
||||
|
||||
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
|
||||
|
Loading…
Reference in New Issue
Block a user