subrepo:
  subdir:   "libopencm3"
  merged:   "f5813a54"
upstream:
  origin:   "https://github.com/libopencm3/libopencm3"
  branch:   "master"
  commit:   "f5813a54"
git-subrepo:
  version:  "0.4.3"
  origin:   "???"
  commit:   "???"
This commit is contained in:
2021-09-30 16:34:10 +03:00
parent 1a441e5806
commit 244fdbc35c
1125 changed files with 185440 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
LIBNAME = libopencm3_stm32l1
SRCLIBDIR ?= ../..
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-Wall -Wextra -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../../include -fno-common \
-mcpu=cortex-m3 $(FP_FLAGS) -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DSTM32L1
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += adc.o adc_common_v1.o adc_common_v1_multi.o
OBJS += flash.o
OBJS += crc_common_all.o
OBJS += dac_common_all.o dac_common_v1.o
OBJS += desig_common_all.o desig.o
OBJS += dma_common_l1f013.o
OBJS += exti_common_all.o
OBJS += flash_common_all.o flash_common_l01.o
OBJS += gpio_common_all.o gpio_common_f0234.o
OBJS += i2c_common_v1.o
OBJS += iwdg_common_all.o
OBJS += lcd.o
OBJS += pwr_common_v1.o pwr_common_v2.o
OBJS += rcc.o rcc_common_all.o
OBJS += rtc_common_l1f024.o
OBJS += spi_common_all.o spi_common_v1.o spi_common_v1_frf.o
OBJS += timer.o timer_common_all.o
OBJS += usart_common_all.o usart_common_f124.o
OBJS += usb.o usb_control.o usb_standard.o usb_msc.o
OBJS += usb_hid.o
OBJS += usb_audio.o usb_cdc.o usb_midi.o
OBJS += st_usbfs_core.o st_usbfs_v1.o
VPATH += ../../usb:../:../../cm3:../common
include ../../Makefile.include

View File

@@ -0,0 +1,90 @@
/** @addtogroup adc_file ADC peripheral API
@ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2014 Karl Palsson <karlp@tweak.net.au>
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2014 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/adc.h>
/**@{*/
/*----------------------------------------------------------------------------*/
/** @brief ADC Set the Sample Time for a Single Channel
The sampling time can be selected in ADC clock cycles from 4 to 384.
@param[in] adc Unsigned int32. ADC block base address @ref adc_reg_base.
@param[in] channel uint8. ADC Channel integer 0..18 or from @ref adc_channel.
@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg.
*/
void adc_set_sample_time(uint32_t adc, uint8_t channel, uint8_t time)
{
uint32_t reg32;
if (channel < 10) {
reg32 = ADC_SMPR3(adc);
reg32 &= ~(0x7 << (channel * 3));
reg32 |= (time << (channel * 3));
ADC_SMPR3(adc) = reg32;
} else if (channel < 20) {
reg32 = ADC_SMPR2(adc);
reg32 &= ~(0x7 << ((channel - 10) * 3));
reg32 |= (time << ((channel - 10) * 3));
ADC_SMPR2(adc) = reg32;
} else {
reg32 = ADC_SMPR1(adc);
reg32 &= ~(0x7 << ((channel - 20) * 3));
reg32 |= (time << ((channel - 20) * 3));
ADC_SMPR1(adc) = reg32;
}
}
/*----------------------------------------------------------------------------*/
/** @brief ADC Set the Sample Time for All Channels
The sampling time can be selected in ADC clock cycles, same for
all channels.
@param[in] adc Unsigned int32. ADC block base address @ref adc_reg_base.
@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg.
*/
void adc_set_sample_time_on_all_channels(uint32_t adc, uint8_t time)
{
uint8_t i;
uint32_t reg32 = 0;
for (i = 0; i <= 9; i++) {
reg32 |= (time << (i * 3));
}
ADC_SMPR0(adc) = reg32;
ADC_SMPR1(adc) = reg32;
ADC_SMPR2(adc) = reg32;
ADC_SMPR3(adc) = reg32;
}
/**@}*/

View File

@@ -0,0 +1,70 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2020 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/assert.h>
#include <libopencm3/stm32/dbgmcu.h>
#include <libopencm3/stm32/desig.h>
uint16_t desig_get_flash_size(void)
{
uint32_t v;
uint32_t device_id = DBGMCU_IDCODE & DBGMCU_IDCODE_DEV_ID_MASK;
switch (device_id) {
case 0x416:
return *(uint32_t*)DESIG_FLASH_SIZE_BASE_CAT12;
case 0x429:
v = *(uint32_t*)DESIG_FLASH_SIZE_BASE_CAT12;
return v & 0xff;
case 0x427:
case 0x437:
return *(uint32_t*)DESIG_FLASH_SIZE_BASE_CAT3456;
case 0x436:
v = *(uint32_t*)DESIG_FLASH_SIZE_BASE_CAT3456;
return v ? 256 : 384;
}
cm3_assert_not_reached();
}
void desig_get_unique_id(uint32_t *result)
{
uint32_t device_id = DBGMCU_IDCODE & DBGMCU_IDCODE_DEV_ID_MASK;
uint32_t* uid_base = 0;
switch (device_id) {
case 0x416:
case 0x429:
uid_base = (uint32_t*)DESIG_UNIQUE_ID_BASE_CAT12;
break;
case 0x427:
case 0x436:
case 0x437:
uid_base = (uint32_t*)DESIG_UNIQUE_ID_BASE_CAT3456;
break;
}
if (!uid_base) {
/* We don't know the address for this device. Hang here to help debugging. */
cm3_assert_not_reached();
}
/* yes, careful with offsets here */
result[0] = uid_base[5];
result[1] = uid_base[1];
result[2] = uid_base[0];
}

View File

@@ -0,0 +1,74 @@
/** @defgroup flash_file FLASH peripheral API
*
* @ingroup peripheral_apis
*
* @brief <b>libopencm3 STM32L1xx FLASH</b>
*
* @version 1.0.0
*
* @author @htmlonly &copy; @endhtmlonly 2010
* Thomas Otto <tommi@viadmin.org>
* @author @htmlonly &copy; @endhtmlonly 2010
* Mark Butler <mbutler@physics.otago.ac.nz>
* @author @htmlonly &copy; @endhtmlonly 2012
* Karl Palsson <karlp@tweak.net.au>
*
* @date 14 January 2014
*
* For the STM32L1xx, accessing FLASH memory is described briefly in
* section 2.3.3 of the STM32L1xx Reference Manual.
* For detailed programming information see:
* PM0062 programming manual: STM32L1xxxx Flash and EEPROM programming
* March 2012, Doc ID 16024 Rev 5
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
* Copyright (C) 2012-13 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/flash.h>
/*---------------------------------------------------------------------------*/
/** @brief Enable 64 Bit Programming Mode
*/
void flash_64bit_enable(void)
{
FLASH_ACR |= FLASH_ACR_ACC64;
}
/*---------------------------------------------------------------------------*/
/** @brief Enable 32 Bit Programming Mode
This mode is a low power mode. It must be used at low frequencies and does not
allow prefetch or wait states to be used.
*/
void flash_64bit_disable(void)
{
FLASH_ACR &= ~FLASH_ACR_ACC64;
}
/**@}*/

View File

@@ -0,0 +1,31 @@
/** @defgroup i2c_file I2C
@ingroup STM32L1xx
@brief <b>libopencm3 STM32L1xx I2C</b>
@version 1.0.0
@date 15 October 2012
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/i2c.h>

View File

@@ -0,0 +1,154 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2014 Nikolay Merinov <nikolay.merinov@member.fsf.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/l1/lcd.h>
#include <libopencm3/stm32/rcc.h>
void lcd_enable(void)
{
LCD_CR |= LCD_CR_LCDEN;
}
void lcd_update(void)
{
LCD_SR |= LCD_SR_UDR;
}
void lcd_wait_for_lcd_enabled(void)
{
while ((LCD_SR & LCD_SR_ENS) == 0);
}
void lcd_wait_for_step_up_ready(void)
{
while ((LCD_SR & LCD_SR_RDY) == 0);
}
void lcd_wait_for_update_ready(void)
{
while ((LCD_SR & LCD_SR_UDR) != 0);
}
int lcd_is_enabled(void)
{
return ((LCD_SR & LCD_SR_ENS) != 0);
}
int lcd_is_step_up_ready(void)
{
return ((LCD_SR & LCD_SR_RDY) != 0);
}
int lcd_is_for_update_ready(void)
{
return ((LCD_SR & LCD_SR_UDR) == 0);
}
void lcd_set_contrast(uint8_t contrast)
{
LCD_FCR &= ~(LCD_FCR_CC_MASK << LCD_FCR_CC_SHIFT);
LCD_FCR |= contrast << LCD_FCR_CC_SHIFT;
}
void lcd_set_bias(uint8_t bias)
{
LCD_CR &= ~(LCD_CR_BIAS_MASK << LCD_CR_BIAS_SHIFT);
LCD_CR |= bias << LCD_CR_BIAS_SHIFT;
}
void lcd_set_duty(uint8_t duty)
{
LCD_CR &= ~(LCD_CR_DUTY_MASK << LCD_CR_DUTY_SHIFT);
LCD_CR |= duty << LCD_CR_DUTY_SHIFT;
}
void lcd_set_prescaler(uint8_t ps)
{
LCD_FCR &= ~(LCD_FCR_PS_MASK << LCD_FCR_PS_SHIFT);
LCD_FCR |= ps << LCD_FCR_PS_SHIFT;
}
void lcd_set_divider(uint8_t div)
{
LCD_FCR &= ~(LCD_FCR_DIV_MASK << LCD_FCR_DIV_SHIFT);
LCD_FCR |= div << LCD_FCR_DIV_SHIFT;
}
void lcd_enable_segment_multiplexing(void)
{
LCD_CR |= LCD_CR_MUX_SEG;
}
void lcd_disable_segment_multiplexing(void)
{
LCD_CR &= ~LCD_CR_MUX_SEG;
}
void lcd_set_refresh_frequency(uint32_t frequency)
{
uint32_t duty, lcd_clock;
switch ((LCD_CR >> LCD_CR_DUTY_SHIFT) & LCD_CR_DUTY_MASK) {
case LCD_CR_DUTY_STATIC:
duty = 1;
break;
case LCD_CR_DUTY_1_2:
duty = 2;
break;
case LCD_CR_DUTY_1_3:
duty = 3;
break;
case LCD_CR_DUTY_1_4:
duty = 4;
break;
case LCD_CR_DUTY_1_8:
duty = 8;
break;
default:
/* Incorrect duty */
return;
}
switch ((RCC_CSR >> RCC_CSR_RTCSEL_SHIFT) & RCC_CSR_RTCSEL_MASK) {
case RCC_CSR_RTCSEL_LSE:
lcd_clock = 32786;
break;
case RCC_CSR_RTCSEL_LSI:
lcd_clock = 37000;
break;
case RCC_CSR_RTCSEL_HSE:
/* no current method of determining clock and divider! */
return;
default:
/* RCC Clock not selected */
return;
}
/* PS * DIV = lcd_clock/(duty * freq) */
uint32_t ps_mul_div = lcd_clock / (duty * frequency);
int div, ps = 0;
while (ps_mul_div > 32) {
ps_mul_div >>= 1;
ps++;
}
div = ps_mul_div - 16;
lcd_set_prescaler(ps);
lcd_set_divider(div);
}

View File

@@ -0,0 +1,610 @@
/** @defgroup rcc_file RCC peripheral API
@ingroup peripheral_apis
@brief <b>libopencm3 STM32L1xx Reset and Clock Control</b>
@version 1.0.0
This library supports the Reset and Clock Control System in the STM32L1xx
series of ARM Cortex Microcontrollers by ST Microelectronics.
Clock settings and resets for many peripherals are given here rather than in
the corresponding peripheral library.
The library also provides a number of common configurations for the processor
system clock. Not all possible configurations are included.
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Federico Ruiz-Ugalde <memeruiz at gmail dot com>
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
* Based on the F4 code...
*/
/**@{*/
#include <libopencm3/cm3/assert.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/flash.h>
#include <libopencm3/stm32/pwr.h>
/* Set the default clock frequencies after reset. */
uint32_t rcc_ahb_frequency = 2097000;
uint32_t rcc_apb1_frequency = 2097000;
uint32_t rcc_apb2_frequency = 2097000;
const struct rcc_clock_scale rcc_clock_config[RCC_CLOCK_CONFIG_END] = {
{ /* 24MHz PLL from HSI */
.pll_source = RCC_CFGR_PLLSRC_HSI_CLK,
.pll_mul = RCC_CFGR_PLLMUL_MUL3,
.pll_div = RCC_CFGR_PLLDIV_DIV2,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_NODIV,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.voltage_scale = PWR_SCALE1,
.flash_waitstates = 1,
.ahb_frequency = 24000000,
.apb1_frequency = 24000000,
.apb2_frequency = 24000000,
},
{ /* 32MHz PLL from HSI */
.pll_source = RCC_CFGR_PLLSRC_HSI_CLK,
.pll_mul = RCC_CFGR_PLLMUL_MUL6,
.pll_div = RCC_CFGR_PLLDIV_DIV3,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_NODIV,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.voltage_scale = PWR_SCALE1,
.flash_waitstates = 1,
.ahb_frequency = 32000000,
.apb1_frequency = 32000000,
.apb2_frequency = 32000000,
},
{ /* 16MHz HSI raw */
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_NODIV,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.voltage_scale = PWR_SCALE1,
.flash_waitstates = 0,
.ahb_frequency = 16000000,
.apb1_frequency = 16000000,
.apb2_frequency = 16000000,
},
{ /* 4MHz HSI raw */
.hpre = RCC_CFGR_HPRE_DIV4,
.ppre1 = RCC_CFGR_PPRE_NODIV,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.voltage_scale = PWR_SCALE1,
.flash_waitstates = 0,
.ahb_frequency = 4000000,
.apb1_frequency = 4000000,
.apb2_frequency = 4000000,
},
{ /* 4MHz MSI raw */
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_NODIV,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.voltage_scale = PWR_SCALE1,
.flash_waitstates = 0,
.ahb_frequency = 4194000,
.apb1_frequency = 4194000,
.apb2_frequency = 4194000,
.msi_range = RCC_ICSCR_MSIRANGE_4MHZ,
},
{ /* 2MHz MSI raw */
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_NODIV,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.voltage_scale = PWR_SCALE1,
.flash_waitstates = 0,
.ahb_frequency = 2097000,
.apb1_frequency = 2097000,
.apb2_frequency = 2097000,
.msi_range = RCC_ICSCR_MSIRANGE_2MHZ,
},
};
void rcc_osc_ready_int_clear(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CIR |= RCC_CIR_PLLRDYC;
break;
case RCC_HSE:
RCC_CIR |= RCC_CIR_HSERDYC;
break;
case RCC_HSI:
RCC_CIR |= RCC_CIR_HSIRDYC;
break;
case RCC_LSE:
RCC_CIR |= RCC_CIR_LSERDYC;
break;
case RCC_LSI:
RCC_CIR |= RCC_CIR_LSIRDYC;
break;
case RCC_MSI:
RCC_CIR |= RCC_CIR_MSIRDYC;
break;
}
}
void rcc_osc_ready_int_enable(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CIR |= RCC_CIR_PLLRDYIE;
break;
case RCC_HSE:
RCC_CIR |= RCC_CIR_HSERDYIE;
break;
case RCC_HSI:
RCC_CIR |= RCC_CIR_HSIRDYIE;
break;
case RCC_LSE:
RCC_CIR |= RCC_CIR_LSERDYIE;
break;
case RCC_LSI:
RCC_CIR |= RCC_CIR_LSIRDYIE;
break;
case RCC_MSI:
RCC_CIR |= RCC_CIR_MSIRDYIE;
break;
}
}
void rcc_osc_ready_int_disable(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CIR &= ~RCC_CIR_PLLRDYIE;
break;
case RCC_HSE:
RCC_CIR &= ~RCC_CIR_HSERDYIE;
break;
case RCC_HSI:
RCC_CIR &= ~RCC_CIR_HSIRDYIE;
break;
case RCC_LSE:
RCC_CIR &= ~RCC_CIR_LSERDYIE;
break;
case RCC_LSI:
RCC_CIR &= ~RCC_CIR_LSIRDYIE;
break;
case RCC_MSI:
RCC_CIR &= ~RCC_CIR_MSIRDYIE;
break;
}
}
int rcc_osc_ready_int_flag(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0);
break;
case RCC_HSE:
return ((RCC_CIR & RCC_CIR_HSERDYF) != 0);
break;
case RCC_HSI:
return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0);
break;
case RCC_LSE:
return ((RCC_CIR & RCC_CIR_LSERDYF) != 0);
break;
case RCC_LSI:
return ((RCC_CIR & RCC_CIR_LSIRDYF) != 0);
break;
case RCC_MSI:
return ((RCC_CIR & RCC_CIR_MSIRDYF) != 0);
break;
}
/* Shouldn't be reached. */
return -1;
}
void rcc_css_int_clear(void)
{
RCC_CIR |= RCC_CIR_CSSC;
}
int rcc_css_int_flag(void)
{
return ((RCC_CIR & RCC_CIR_CSSF) != 0);
}
bool rcc_is_osc_ready(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
return RCC_CR & RCC_CR_PLLRDY;
case RCC_HSE:
return RCC_CR & RCC_CR_HSERDY;
case RCC_HSI:
return RCC_CR & RCC_CR_HSIRDY;
case RCC_MSI:
return RCC_CR & RCC_CR_MSIRDY;
case RCC_LSE:
return RCC_CSR & RCC_CSR_LSERDY;
case RCC_LSI:
return RCC_CSR & RCC_CSR_LSIRDY;
}
return false;
}
void rcc_wait_for_osc_ready(enum rcc_osc osc)
{
while (!rcc_is_osc_ready(osc));
}
void rcc_wait_for_sysclk_status(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SWS_MASK) !=
RCC_CFGR_SWS_SYSCLKSEL_PLLCLK);
break;
case RCC_HSE:
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SWS_MASK) !=
RCC_CFGR_SWS_SYSCLKSEL_HSECLK);
break;
case RCC_HSI:
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SWS_MASK) !=
RCC_CFGR_SWS_SYSCLKSEL_HSICLK);
break;
case RCC_MSI:
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SWS_MASK) !=
RCC_CFGR_SWS_SYSCLKSEL_MSICLK);
break;
default:
/* Shouldn't be reached. */
break;
}
}
void rcc_osc_on(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CR |= RCC_CR_PLLON;
break;
case RCC_MSI:
RCC_CR |= RCC_CR_MSION;
break;
case RCC_HSE:
RCC_CR |= RCC_CR_HSEON;
break;
case RCC_HSI:
RCC_CR |= RCC_CR_HSION;
break;
case RCC_LSE:
RCC_CSR |= RCC_CSR_LSEON;
break;
case RCC_LSI:
RCC_CSR |= RCC_CSR_LSION;
break;
}
}
void rcc_osc_off(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CR &= ~RCC_CR_PLLON;
break;
case RCC_MSI:
RCC_CR &= ~RCC_CR_MSION;
break;
case RCC_HSE:
RCC_CR &= ~RCC_CR_HSEON;
break;
case RCC_HSI:
RCC_CR &= ~RCC_CR_HSION;
break;
case RCC_LSE:
RCC_CSR &= ~RCC_CSR_LSEON;
break;
case RCC_LSI:
RCC_CSR &= ~RCC_CSR_LSION;
break;
}
}
void rcc_css_enable(void)
{
RCC_CR |= RCC_CR_CSSON;
}
void rcc_css_disable(void)
{
RCC_CR &= ~RCC_CR_CSSON;
}
/**
* Set the range of the MSI oscillator
* @param range desired range @ref rcc_icscr_msirange
*/
void rcc_set_msi_range(uint32_t range)
{
uint32_t reg = RCC_ICSCR;
reg &= ~(RCC_ICSCR_MSIRANGE_MASK << RCC_ICSCR_MSIRANGE_SHIFT);
reg |= (range << RCC_ICSCR_MSIRANGE_SHIFT);
RCC_ICSCR = reg;
}
void rcc_set_sysclk_source(uint32_t clk)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~(RCC_CFGR_SW_MASK << RCC_CFGR_SW_SHIFT);
RCC_CFGR = (reg32 | clk << RCC_CFGR_SW_SHIFT);
}
void rcc_set_pll_configuration(uint32_t source, uint32_t multiplier,
uint32_t divisor)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~(RCC_CFGR_PLLDIV_MASK << RCC_CFGR_PLLDIV_SHIFT);
reg32 &= ~(RCC_CFGR_PLLMUL_MASK << RCC_CFGR_PLLMUL_SHIFT);
reg32 &= ~(1 << 16);
reg32 |= (source << 16);
reg32 |= (multiplier << RCC_CFGR_PLLMUL_SHIFT);
reg32 |= (divisor << RCC_CFGR_PLLDIV_SHIFT);
RCC_CFGR = reg32;
}
void rcc_set_pll_source(uint32_t pllsrc)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~(1 << 16);
RCC_CFGR = (reg32 | (pllsrc << 16));
}
void rcc_set_ppre2(uint32_t ppre2)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~(RCC_CFGR_PPRE2_MASK << RCC_CFGR_PPRE2_SHIFT);
RCC_CFGR = (reg32 | (ppre2 << RCC_CFGR_PPRE2_SHIFT));
}
void rcc_set_ppre1(uint32_t ppre1)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~(RCC_CFGR_PPRE1_MASK << RCC_CFGR_PPRE1_SHIFT);
RCC_CFGR = (reg32 | (ppre1 << RCC_CFGR_PPRE1_SHIFT));
}
void rcc_set_hpre(uint32_t hpre)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~(RCC_CFGR_HPRE_MASK << RCC_CFGR_HPRE_SHIFT);
RCC_CFGR = (reg32 | (hpre << RCC_CFGR_HPRE_SHIFT));
}
void rcc_set_rtcpre(uint32_t rtcpre)
{
uint32_t reg32;
reg32 = RCC_CR;
reg32 &= ~(RCC_CR_RTCPRE_MASK << RCC_CR_RTCPRE_SHIFT);
RCC_CR = (reg32 | (rtcpre << RCC_CR_RTCPRE_SHIFT));
}
uint32_t rcc_system_clock_source(void)
{
/* Return the clock source which is used as system clock. */
return (RCC_CFGR & 0x000c) >> 2;
}
void rcc_rtc_select_clock(uint32_t clock)
{
RCC_CSR &= ~(RCC_CSR_RTCSEL_MASK << RCC_CSR_RTCSEL_SHIFT);
RCC_CSR |= (clock << RCC_CSR_RTCSEL_SHIFT);
}
void rcc_clock_setup_msi(const struct rcc_clock_scale *clock)
{
/* Enable internal multi-speed oscillator. */
rcc_set_msi_range(clock->msi_range);
rcc_osc_on(RCC_MSI);
rcc_wait_for_osc_ready(RCC_MSI);
/* Select MSI as SYSCLK source. */
rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_MSICLK);
/*
* Set prescalers for AHB, ADC, APB1, APB2.
* Do this before touching the PLL (TODO: why?).
*/
rcc_set_hpre(clock->hpre);
rcc_set_ppre1(clock->ppre1);
rcc_set_ppre2(clock->ppre2);
rcc_periph_clock_enable(RCC_PWR);
pwr_set_vos_scale(clock->voltage_scale);
/* I guess this should be in the settings? */
flash_64bit_enable();
flash_prefetch_enable();
flash_set_ws(clock->flash_waitstates);
/* Set the peripheral clock frequencies used. */
rcc_ahb_frequency = clock->ahb_frequency;
rcc_apb1_frequency = clock->apb1_frequency;
rcc_apb2_frequency = clock->apb2_frequency;
}
/**
* Switch sysclock to HSI with the given parameters.
* This should be usable from any point in time, but only if you have used
* library functions to manage clocks. It relies on the global
* @ref rcc_ahb_frequency to ensure that it reliably scales voltage up or down
* as appropriate.
* @param clock full struct with desired parameters
*/
void rcc_clock_setup_hsi(const struct rcc_clock_scale *clock)
{
/* Enable internal high-speed oscillator. */
rcc_osc_on(RCC_HSI);
rcc_periph_clock_enable(RCC_PWR);
/* I guess this should be in the settings? */
flash_64bit_enable();
flash_prefetch_enable();
/* Don't try and go to fast for a voltage range! */
if (clock->ahb_frequency > rcc_ahb_frequency) {
/* Going up, power up first */
pwr_set_vos_scale(clock->voltage_scale);
rcc_set_hpre(clock->hpre);
rcc_set_ppre1(clock->ppre1);
rcc_set_ppre2(clock->ppre2);
flash_set_ws(clock->flash_waitstates);
} else {
/* going down, slow down before cutting power */
rcc_set_hpre(clock->hpre);
rcc_set_ppre1(clock->ppre1);
rcc_set_ppre2(clock->ppre2);
flash_set_ws(clock->flash_waitstates);
pwr_set_vos_scale(clock->voltage_scale);
}
rcc_wait_for_osc_ready(RCC_HSI);
while (PWR_CSR & PWR_CSR_VOSF) {
;
}
rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
/* Set the peripheral clock frequencies used. */
rcc_ahb_frequency = clock->ahb_frequency;
rcc_apb1_frequency = clock->apb1_frequency;
rcc_apb2_frequency = clock->apb2_frequency;
}
void rcc_clock_setup_pll(const struct rcc_clock_scale *clock)
{
/* Turn on the appropriate source for the PLL */
if (clock->pll_source == RCC_CFGR_PLLSRC_HSE_CLK) {
rcc_osc_on(RCC_HSE);
rcc_wait_for_osc_ready(RCC_HSE);
} else {
rcc_osc_on(RCC_HSI);
rcc_wait_for_osc_ready(RCC_HSI);
}
/*
* Set prescalers for AHB, ADC, APB1, APB2.
* Do this before touching the PLL (TODO: why?).
*/
rcc_set_hpre(clock->hpre);
rcc_set_ppre1(clock->ppre1);
rcc_set_ppre2(clock->ppre2);
rcc_periph_clock_enable(RCC_PWR);
pwr_set_vos_scale(clock->voltage_scale);
/* I guess this should be in the settings? */
flash_64bit_enable();
flash_prefetch_enable();
flash_set_ws(clock->flash_waitstates);
/* Disable PLL oscillator before changing its configuration. */
rcc_osc_off(RCC_PLL);
/* Configure the PLL oscillator. */
rcc_set_pll_configuration(clock->pll_source, clock->pll_mul,
clock->pll_div);
/* Enable PLL oscillator and wait for it to stabilize. */
rcc_osc_on(RCC_PLL);
rcc_wait_for_osc_ready(RCC_PLL);
/* Select PLL as SYSCLK source. */
rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
/* Set the peripheral clock frequencies used. */
rcc_ahb_frequency = clock->ahb_frequency;
rcc_apb1_frequency = clock->apb1_frequency;
rcc_apb2_frequency = clock->apb2_frequency;
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the USART at base specified.
* @param usart Base address of USART to get clock frequency for.
*/
uint32_t rcc_get_usart_clk_freq(uint32_t usart)
{
if (usart == USART1_BASE) {
return rcc_apb2_frequency;
} else {
return rcc_apb1_frequency;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the Timer at base specified.
* @param timer Base address of TIM to get clock frequency for.
*/
uint32_t rcc_get_timer_clk_freq(uint32_t timer)
{
/* Handle APB1 timers, and apply multiplier if necessary. */
if (timer >= TIM2_BASE && timer <= TIM7_BASE) {
uint8_t ppre1 = (RCC_CFGR >> RCC_CFGR_PPRE1_SHIFT) & RCC_CFGR_PPRE1_MASK;
return (ppre1 == RCC_CFGR_PPRE1_HCLK_NODIV) ? rcc_apb1_frequency
: 2 * rcc_apb1_frequency;
} else {
uint8_t ppre2 = (RCC_CFGR >> RCC_CFGR_PPRE2_SHIFT) & RCC_CFGR_PPRE2_MASK;
return (ppre2 == RCC_CFGR_PPRE2_HCLK_NODIV) ? rcc_apb2_frequency
: 2 * rcc_apb2_frequency;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the I2C device at base specified.
* @param i2c Base address of I2C to get clock frequency for.
*/
uint32_t rcc_get_i2c_clk_freq(uint32_t i2c __attribute__((unused)))
{
return rcc_apb1_frequency;
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the SPI device at base specified.
* @param spi Base address of SPI device to get clock frequency for (e.g. SPI1_BASE).
*/
uint32_t rcc_get_spi_clk_freq(uint32_t spi) {
if (spi == SPI1_BASE) {
return rcc_apb2_frequency;
} else {
return rcc_apb1_frequency;
}
}
/**@}*/

View File

@@ -0,0 +1,56 @@
/** @defgroup timer_file TIMER peripheral API
@ingroup peripheral_apis
@brief <b>libopencm3 STM32L1xx Timers</b>
@version 1.0.0
@date 18 August 2012
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Edward Cheeseman <evbuilder@users.sourceforge.org>
* Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/timer.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief Set Timer Option
Set timer options register on TIM2 or TIM3, used for trigger remapping.
@param[in] timer_peripheral Unsigned int32. Timer register address base
@param[in] option Desired option @ref tim2_opt_trigger_remap and @ref tim3_opt_trigger_remap
*/
void timer_set_option(uint32_t timer_peripheral, uint32_t option)
{
if (timer_peripheral == TIM2) {
TIM_OR(timer_peripheral) &= ~TIM2_OR_ITR1_RMP_MASK;
TIM_OR(timer_peripheral) |= option;
} else if (timer_peripheral == TIM3) {
TIM_OR(timer_peripheral) &= ~TIM3_OR_ITR2_RMP_MASK;
TIM_OR(timer_peripheral) |= option;
}
}
/**@}*/