summaryrefslogtreecommitdiffstats
path: root/libopencm3/lib/stm32/common
diff options
context:
space:
mode:
Diffstat (limited to 'libopencm3/lib/stm32/common')
-rw-r--r--libopencm3/lib/stm32/common/adc_common_v1.c755
-rw-r--r--libopencm3/lib/stm32/common/crc_common_all.c81
-rw-r--r--libopencm3/lib/stm32/common/crypto_common_f24.c175
-rw-r--r--libopencm3/lib/stm32/common/dac_common_all.c503
-rw-r--r--libopencm3/lib/stm32/common/dma_common_f24.c794
-rw-r--r--libopencm3/lib/stm32/common/dma_common_l1f013.c435
-rw-r--r--libopencm3/lib/stm32/common/exti_common_all.c154
-rw-r--r--libopencm3/lib/stm32/common/flash_common_f01.c235
-rw-r--r--libopencm3/lib/stm32/common/flash_common_f234.c121
-rw-r--r--libopencm3/lib/stm32/common/flash_common_f24.c416
-rw-r--r--libopencm3/lib/stm32/common/gpio_common_all.c151
-rw-r--r--libopencm3/lib/stm32/common/gpio_common_f0234.c206
-rw-r--r--libopencm3/lib/stm32/common/hash_common_f24.c163
-rw-r--r--libopencm3/lib/stm32/common/i2c_common_all.c419
-rw-r--r--libopencm3/lib/stm32/common/iwdg_common_all.c149
-rw-r--r--libopencm3/lib/stm32/common/pwr_common_all.c205
-rw-r--r--libopencm3/lib/stm32/common/rcc_common_all.c188
-rw-r--r--libopencm3/lib/stm32/common/rtc_common_l1f024.c123
-rw-r--r--libopencm3/lib/stm32/common/spi_common_all.c710
-rw-r--r--libopencm3/lib/stm32/common/spi_common_f03.c177
-rw-r--r--libopencm3/lib/stm32/common/spi_common_l1f124.c137
-rw-r--r--libopencm3/lib/stm32/common/timer_common_all.c2177
-rw-r--r--libopencm3/lib/stm32/common/timer_common_f234.c58
-rw-r--r--libopencm3/lib/stm32/common/timer_common_f24.c53
-rw-r--r--libopencm3/lib/stm32/common/usart_common_all.c367
-rw-r--r--libopencm3/lib/stm32/common/usart_common_f124.c143
26 files changed, 9095 insertions, 0 deletions
diff --git a/libopencm3/lib/stm32/common/adc_common_v1.c b/libopencm3/lib/stm32/common/adc_common_v1.c
new file mode 100644
index 0000000..a4b9257
--- /dev/null
+++ b/libopencm3/lib/stm32/common/adc_common_v1.c
@@ -0,0 +1,755 @@
+/** @addtogroup adc_file
+
+@author @htmlonly © @endhtmlonly
+2009 Edward Cheeseman <evbuilder@users.sourceforge.net>
+@author @htmlonly &copy; @endhtmlonly
+2012 Ken Sarkies <ksarkies@internode.on.net>
+@author @htmlonly &copy; @endhtmlonly
+2014 Karl Palsson <karlp@tweak.net.au>
+
+This library supports one style of the Analog to Digital Conversion System in
+the STM32 series of ARM Cortex Microcontrollers by ST Microelectronics.
+
+The style of ADC Peripheral supported by this code is found in the F1, F2,
+F37x, F38x, F4, and L1 series devices (at the time of writing) but is quite
+different to the style found on the F0 and F30x and F31x.
+Devices can have up to three A/D converters each with their own set of
+registers.
+However all the A/D converters share a common clock. On most devices, this is
+prescaled from the APB2 clock by default by a minimum factor of 2 to a maximum
+of 8, though on the L1 this is always a divider from the HSI. (And therefore HSI
+_must_ be enabled before attempting to enable the ADC)
+
+Each A/D converter has up to ADC_MAX_CHANNELS channels:
+@li On ADC1 the analog channels 16 and 17 are internally connected to the
+temperature sensor and V<sub>REFINT</sub>, respectively.
+@li On ADC2 (if available) the analog channels 16 and 17 are internally
+connected to V<sub>SS</sub>.
+@li On ADC3 (if available) the analog channels 9, 14, 15, 16 and 17 are
+internally connected to V<sub>SS</sub>.
+
+The conversions can occur as a one-off conversion whereby the process stops once
+conversion is complete. The conversions can also be continuous wherein a new
+conversion starts immediately the previous conversion has ended.
+
+Conversion can occur as a single channel conversion or a scan of a group of
+channels in either continuous or one-off mode. If more than one channel is
+converted in a scan group, DMA must be used to transfer the data as there is
+only one result register available. An interrupt can be set to occur at the end
+of conversion, which occurs after all channels have been scanned.
+
+A discontinuous mode allows a subgroup of group of a channels to be converted in
+bursts of a given length.
+
+Injected conversions allow a second group of channels to be converted separately
+from the regular group. An interrupt can be set to occur at the end of
+conversion, which occurs after all channels have been scanned.
+
+@section adc_api_ex Basic ADC Handling API.
+
+Example 1: Simple single channel conversion polled. Enable the peripheral clock
+and ADC, reset ADC and set the prescaler divider. Set dual mode to independent
+(default). Enable triggering for a software trigger.
+
+@code
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_ADC1EN);
+ adc_off(ADC1);
+ rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_ADC1RST);
+ rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_ADC1RST);
+ rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV2);
+ adc_set_dual_mode(ADC_CR1_DUALMOD_IND);
+ adc_disable_scan_mode(ADC1);
+ adc_set_single_conversion_mode(ADC1);
+ adc_set_sample_time(ADC1, ADC_CHANNEL0, ADC_SMPR1_SMP_1DOT5CYC);
+ adc_set_single_channel(ADC1, ADC_CHANNEL0);
+ adc_enable_trigger(ADC1, ADC_CR2_EXTSEL_SWSTART);
+ adc_power_on(ADC1);
+ adc_reset_calibration(ADC1);
+ adc_calibration(ADC1);
+ adc_start_conversion_regular(ADC1);
+ while (! adc_eoc(ADC1));
+ reg16 = adc_read_regular(ADC1);
+@endcode
+
+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 Off
+
+Turn off the ADC to reduce power consumption to a few microamps.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_off(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_ADON;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog for Regular Conversions
+
+The analog watchdog allows the monitoring of an analog signal between two
+threshold levels. The thresholds must be preset. Comparison is done before data
+alignment takes place, so the thresholds are left-aligned.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_enable_analog_watchdog_regular(uint32_t adc)
+{
+ ADC_CR1(adc) |= ADC_CR1_AWDEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Analog Watchdog for Regular Conversions
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_disable_analog_watchdog_regular(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_AWDEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog for Injected Conversions
+
+The analog watchdog allows the monitoring of an analog signal between two
+threshold levels. The thresholds must be preset. Comparison is done before data
+alignment takes place, so the thresholds are left-aligned.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_analog_watchdog_injected(uint32_t adc)
+{
+ ADC_CR1(adc) |= ADC_CR1_JAWDEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Analog Watchdog for Injected Conversions
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_analog_watchdog_injected(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_JAWDEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Discontinuous Mode for Regular Conversions
+
+In this mode the ADC converts, on each trigger, a subgroup of up to 8 of the
+defined regular channel group. The subgroup is defined by the number of
+consecutive channels to be converted. After a subgroup has been converted
+the next trigger will start conversion of the immediately following subgroup
+of the same length or until the whole group has all been converted. When the
+the whole group has been converted, the next trigger will restart conversion
+of the subgroup at the beginning of the whole group.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] length Unsigned int8. Number of channels in the group @ref
+adc_cr1_discnum
+*/
+
+void adc_enable_discontinuous_mode_regular(uint32_t adc, uint8_t length)
+{
+ if ((length-1) > 7) {
+ return;
+ }
+ ADC_CR1(adc) |= ADC_CR1_DISCEN;
+ ADC_CR1(adc) |= ((length-1) << ADC_CR1_DISCNUM_SHIFT);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Discontinuous Mode for Regular Conversions
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_discontinuous_mode_regular(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_DISCEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Discontinuous Mode for Injected Conversions
+
+In this mode the ADC converts sequentially one channel of the defined group of
+injected channels, cycling back to the first channel in the group once the
+entire group has been converted.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_discontinuous_mode_injected(uint32_t adc)
+{
+ ADC_CR1(adc) |= ADC_CR1_JDISCEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Discontinuous Mode for Injected Conversions
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_discontinuous_mode_injected(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_JDISCEN;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Automatic Injected Conversions
+
+The ADC converts a defined injected group of channels immediately after the
+regular channels have been converted. The external trigger on the injected
+channels is disabled as required.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_automatic_injected_group_conversion(uint32_t adc)
+{
+ adc_disable_external_trigger_injected(adc);
+ ADC_CR1(adc) |= ADC_CR1_JAUTO;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Automatic Injected Conversions
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_automatic_injected_group_conversion(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_JAUTO;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog for All Regular and/or Injected Channels
+
+The analog watchdog allows the monitoring of an analog signal between two
+threshold levels. The thresholds must be preset. Comparison is done before data
+alignment takes place, so the thresholds are left-aligned.
+
+@note The analog watchdog must be enabled for either or both of the regular or
+injected channels. If neither are enabled, the analog watchdog feature will be
+disabled.
+@ref adc_enable_analog_watchdog_injected, @ref
+adc_enable_analog_watchdog_regular.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_analog_watchdog_on_all_channels(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_AWDSGL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog for a Selected Channel
+
+The analog watchdog allows the monitoring of an analog signal between two
+threshold levels. The thresholds must be preset. Comparison is done before data
+alignment takes place, so the thresholds are left-aligned.
+
+@note The analog watchdog must be enabled for either or both of the regular or
+injected channels. If neither are enabled, the analog watchdog feature will be
+disabled. If both are enabled, the same channel number is monitored.
+@ref adc_enable_analog_watchdog_injected, @ref
+adc_enable_analog_watchdog_regular.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] channel Unsigned int8. ADC channel number @ref adc_watchdog_channel
+*/
+
+void adc_enable_analog_watchdog_on_selected_channel(uint32_t adc,
+ uint8_t channel)
+{
+ uint32_t reg32;
+
+ reg32 = (ADC_CR1(adc) & ~ADC_CR1_AWDCH_MASK); /* Clear bits [4:0]. */
+ if (channel <= ADC_CR1_AWDCH_MAX) {
+ reg32 |= channel;
+ }
+ ADC_CR1(adc) = reg32;
+ ADC_CR1(adc) |= ADC_CR1_AWDSGL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Scan Mode
+
+In this mode a conversion consists of a scan of the predefined set of channels,
+regular and injected, each channel conversion immediately following the
+previous one. It can use single, continuous or discontinuous mode.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_scan_mode(uint32_t adc)
+{
+ ADC_CR1(adc) |= ADC_CR1_SCAN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Scan Mode
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_scan_mode(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_SCAN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Injected End-Of-Conversion Interrupt
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_eoc_interrupt_injected(uint32_t adc)
+{
+ ADC_CR1(adc) |= ADC_CR1_JEOCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Injected End-Of-Conversion Interrupt
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_eoc_interrupt_injected(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_JEOCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Analog Watchdog Interrupt
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_awd_interrupt(uint32_t adc)
+{
+ ADC_CR1(adc) |= ADC_CR1_AWDIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Analog Watchdog Interrupt
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_awd_interrupt(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_AWDIE;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Regular End-Of-Conversion Interrupt
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_eoc_interrupt(uint32_t adc)
+{
+ ADC_CR1(adc) |= ADC_CR1_EOCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable Regular End-Of-Conversion Interrupt
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_eoc_interrupt(uint32_t adc)
+{
+ ADC_CR1(adc) &= ~ADC_CR1_EOCIE;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set the Data as Left Aligned
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_set_left_aligned(uint32_t adc)
+{
+ ADC_CR2(adc) |= ADC_CR2_ALIGN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set the Data as Right Aligned
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_set_right_aligned(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_ALIGN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read the End-of-Conversion Flag
+
+This flag is set after all channels of a regular or injected group have been
+converted.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@returns bool. End of conversion flag.
+*/
+
+bool adc_eoc(uint32_t adc)
+{
+ return (ADC_SR(adc) & ADC_SR_EOC) != 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read the End-of-Conversion Flag for Injected Conversion
+
+This flag is set after all channels of an injected group have been converted.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@returns bool. End of conversion flag.
+*/
+
+bool adc_eoc_injected(uint32_t adc)
+{
+ return (ADC_SR(adc) & ADC_SR_JEOC) != 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read from the Regular Conversion Result Register
+
+The result read back is 12 bits, right or left aligned within the first 16 bits.
+For ADC1 only, the higher 16 bits will hold the result from ADC2 if
+an appropriate dual mode has been set @see adc_set_dual_mode.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@returns Unsigned int32 conversion result.
+*/
+
+uint32_t adc_read_regular(uint32_t adc)
+{
+ return ADC_DR(adc);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Read from an Injected Conversion Result Register
+
+The result read back from the selected injected result register (one of four)
+is 12 bits, right or left aligned within the first 16 bits. The result can have
+a negative value if the injected channel offset has been set @see
+adc_set_injected_offset.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] reg Unsigned int8. Register number (1 ... 4).
+@returns Unsigned int32 conversion result.
+*/
+
+uint32_t adc_read_injected(uint32_t adc, uint8_t reg)
+{
+ switch (reg) {
+ case 1:
+ return ADC_JDR1(adc);
+ case 2:
+ return ADC_JDR2(adc);
+ case 3:
+ return ADC_JDR3(adc);
+ case 4:
+ return ADC_JDR4(adc);
+ }
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Continuous Conversion Mode
+
+In this mode the ADC starts a new conversion of a single channel or a channel
+group immediately following completion of the previous channel group conversion.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_set_continuous_conversion_mode(uint32_t adc)
+{
+ ADC_CR2(adc) |= ADC_CR2_CONT;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable Single Conversion Mode
+
+In this mode the ADC performs a conversion of one channel or a channel group
+and stops.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_set_single_conversion_mode(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_CONT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Analog Watchdog Upper Threshold
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] threshold Unsigned int8. Upper threshold value
+*/
+
+void adc_set_watchdog_high_threshold(uint32_t adc, uint16_t threshold)
+{
+ uint32_t reg32 = 0;
+
+ reg32 = (uint32_t)threshold;
+ reg32 &= ADC_HT_MSK;
+ ADC_HTR(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set Analog Watchdog Lower Threshold
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] threshold Unsigned int8. Lower threshold value
+*/
+
+void adc_set_watchdog_low_threshold(uint32_t adc, uint16_t threshold)
+{
+ uint32_t reg32 = 0;
+
+ reg32 = (uint32_t)threshold;
+ reg32 &= ADC_LT_MSK;
+ ADC_LTR(adc) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/** @brief ADC Set a Regular Channel Conversion Sequence
+
+Define a sequence of channels to be converted as a regular group with a length
+from 1 to ADC_REGULAR_SEQUENCE_MAX channels. If this is called during
+conversion, the current conversion is reset and conversion begins again with
+the newly defined group.
+
+@param[in] adc Unsigned int32. ADC block base address @ref adc_reg_base.
+@param[in] length Unsigned int8. Number of channels in the group.
+@param[in] channel Unsigned int8[]. Set of channels in sequence, integers 0..31.
+ */
+
+void adc_set_regular_sequence(uint32_t adc, uint8_t length, uint8_t channel[])
+{
+ uint32_t fifth6 = 0;
+ uint32_t fourth6 = 0;
+ uint32_t third6 = 0;
+ uint32_t second6 = 0;
+ uint32_t first6 = 0;
+ uint8_t i = 0;
+
+ if (length > ADC_SQR_MAX_CHANNELS_REGULAR) {
+ return;
+ }
+
+ for (i = 1; i <= length; i++) {
+ if (i <= 6) {
+ first6 |= (channel[i - 1] << ((i - 1) * 5));
+ }
+ if ((i > 6) & (i <= 12)) {
+ second6 |= (channel[i - 1] << ((i - 6 - 1) * 5));
+ }
+ if ((i > 12) & (i <= 18)) {
+ third6 |= (channel[i - 1] << ((i - 12 - 1) * 5));
+ }
+ if ((i > 18) & (i <= 24)) {
+ fourth6 |= (channel[i - 1] << ((i - 18 - 1) * 5));
+ }
+ if ((i > 24) & (i <= 28)) {
+ fifth6 |= (channel[i - 1] << ((i - 24 - 1) * 5));
+ }
+ }
+#if defined(ADC_SQR5)
+ ADC_SQR1(adc) = fifth6 | ((length - 1) << ADC_SQR1_L_LSB);
+ ADC_SQR2(adc) = fourth6;
+ ADC_SQR3(adc) = third6;
+ ADC_SQR4(adc) = second6;
+ ADC_SQR5(adc) = first6;
+#else
+ ADC_SQR1(adc) = third6 | ((length - 1) << ADC_SQR1_L_LSB);
+ ADC_SQR2(adc) = second6;
+ ADC_SQR3(adc) = first6;
+#endif
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Set an Injected Channel Conversion Sequence
+
+Defines a sequence of channels to be converted as an injected group with a
+length from 1 to 4 channels. If this is called during conversion, the current
+conversion is reset and conversion begins again with the newly defined group.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] length Unsigned int8. Number of channels in the group.
+@param[in] channel Unsigned int8[]. Set of channels in sequence, integers 0..18
+*/
+
+void adc_set_injected_sequence(uint32_t adc, uint8_t length, uint8_t channel[])
+{
+ uint32_t reg32 = 0;
+ uint8_t i = 0;
+
+ /* Maximum sequence length is 4 channels. Minimum sequence is 1.*/
+ if ((length - 1) > 3) {
+ return;
+ }
+
+ for (i = 0; i < length; i++) {
+ reg32 |= ADC_JSQR_JSQ_VAL(4 - i, channel[length - i - 1]);
+ }
+
+ reg32 |= ADC_JSQR_JL_VAL(length);
+
+ ADC_JSQR(adc) = reg32;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/** @brief ADC Set the Injected Channel Data Offset
+
+This value is subtracted from the injected channel results after conversion is
+complete, and can result in negative results. A separate value can be specified
+for each injected data register.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] reg Unsigned int8. Register number (1 ... 4).
+@param[in] offset Unsigned int32.
+*/
+
+void adc_set_injected_offset(uint32_t adc, uint8_t reg, uint32_t offset)
+{
+ switch (reg) {
+ case 1:
+ ADC_JOFR1(adc) = offset;
+ break;
+ case 2:
+ ADC_JOFR2(adc) = offset;
+ break;
+ case 3:
+ ADC_JOFR3(adc) = offset;
+ break;
+ case 4:
+ ADC_JOFR4(adc) = offset;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Software Triggered Conversion on Regular Channels
+
+This starts conversion on a set of defined regular channels if the ADC trigger
+is set to be a software trigger. It is cleared by hardware once conversion
+starts.
+
+Special F1 Note this is a software trigger and requires triggering to be
+enabled and the trigger source to be set appropriately otherwise conversion
+will not start. This is not the same as the ADC start conversion operation.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_start_conversion_regular(uint32_t adc)
+{
+ /* Start conversion on regular channels. */
+ ADC_CR2(adc) |= ADC_CR2_SWSTART;
+
+ /* Wait until the ADC starts the conversion. */
+ while (ADC_CR2(adc) & ADC_CR2_SWSTART);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Software Triggered Conversion on Injected Channels
+
+This starts conversion on a set of defined injected channels if the ADC trigger
+is set to be a software trigger. It is cleared by hardware once conversion
+starts.
+
+Special F1 Note this is a software trigger and requires triggering to be
+enabled and the trigger source to be set appropriately otherwise conversion
+will not start. This is not the same as the ADC start conversion operation.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref
+adc_reg_base.
+*/
+
+void adc_start_conversion_injected(uint32_t adc)
+{
+ /* Start conversion on injected channels. */
+ ADC_CR2(adc) |= ADC_CR2_JSWSTART;
+
+ /* Wait until the ADC starts the conversion. */
+ while (ADC_CR2(adc) & ADC_CR2_JSWSTART);
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Enable DMA Transfers
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_enable_dma(uint32_t adc)
+{
+ ADC_CR2(adc) |= ADC_CR2_DMA;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief ADC Disable DMA Transfers
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
+void adc_disable_dma(uint32_t adc)
+{
+ ADC_CR2(adc) &= ~ADC_CR2_DMA;
+}
+
+
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/common/crc_common_all.c b/libopencm3/lib/stm32/common/crc_common_all.c
new file mode 100644
index 0000000..5794c8f
--- /dev/null
+++ b/libopencm3/lib/stm32/common/crc_common_all.c
@@ -0,0 +1,81 @@
+/** @addtogroup crc_file
+
+@author @htmlonly &copy; @endhtmlonly 2012 Karl Palsson <karlp@remake.is>
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Karl Palsson <karlp@remake.is>
+ *
+ * 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/crc.h>
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief CRC Reset.
+
+Reset the CRC unit and forces the data register to all 1s.
+
+*/
+
+void crc_reset(void)
+{
+ CRC_CR |= CRC_CR_RESET;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief CRC Calculate.
+
+Writes a data word to the register, the write operation stalling until the
+computation is complete.
+
+@param[in] data Unsigned int32.
+@returns int32 Computed CRC result
+*/
+
+uint32_t crc_calculate(uint32_t data)
+{
+ CRC_DR = data;
+ /* Data sheet says this blocks until it's ready.... */
+ return CRC_DR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief CRC Calculate of a Block of Data.
+
+Writes data words consecutively to the register, the write operation stalling
+until the computation of each word is complete.
+
+@param[in] datap Unsigned int32. pointer to an array of 32 bit data words.
+@param[in] size int. Size of the array.
+@returns int32 Final computed CRC result
+*/
+
+uint32_t crc_calculate_block(uint32_t *datap, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ CRC_DR = datap[i];
+ }
+
+ return CRC_DR;
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/crypto_common_f24.c b/libopencm3/lib/stm32/common/crypto_common_f24.c
new file mode 100644
index 0000000..46cef6b
--- /dev/null
+++ b/libopencm3/lib/stm32/common/crypto_common_f24.c
@@ -0,0 +1,175 @@
+/** @addtogroup crypto_file
+ *
+ * @brief <b>libopencm3 STM32 Cryptographic controller</b>
+ *
+ * @version 1.0.0
+ *
+ * @date 17 Jun 2013
+ *
+ * This library supports the cryptographic coprocessor system for the
+ * STM32 series of ARM Cortex Microcontrollers
+ *
+ * LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * 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/crypto.h>
+
+#define CRYP_CR_ALGOMODE_MASK ((1 << 19) | CRYP_CR_ALGOMODE)
+
+/**
+ * @brief Wait, if the Controller is busy
+ */
+void crypto_wait_busy(void)
+{
+ while (CRYP_SR & CRYP_SR_BUSY);
+}
+
+/**
+ * @brief Set key value to the controller
+ * @param[in] keysize enum crypto_keysize Specified size of the key.
+ * @param[in] key uint64_t[] Key value (array of 4 items)
+ */
+void crypto_set_key(enum crypto_keysize keysize, uint64_t key[])
+{
+ int i;
+
+ crypto_wait_busy();
+
+ CRYP_CR = (CRYP_CR & ~CRYP_CR_KEYSIZE) |
+ (keysize << CRYP_CR_KEYSIZE_SHIFT);
+
+ for (i = 0; i < 4; i++) {
+ CRYP_KR(i) = key[i];
+ }
+}
+
+/**
+ * @brief Set Initialization Vector
+ *
+ * @param[in] iv uint64_t[] Initialization vector (array of 4 items)
+
+ * @note Cryptographic controller must be in disabled state
+ */
+void crypto_set_iv(uint64_t iv[])
+{
+ int i;
+
+ crypto_wait_busy();
+
+ for (i = 0; i < 4; i++) {
+ CRYP_IVR(i) = iv[i];
+ }
+}
+
+/**
+ * @brief Set the order of the data to be crypted
+ *
+ * @param[in] datatype enum crypto_datatype Specified datatype of the key.
+ */
+void crypto_set_datatype(enum crypto_datatype datatype)
+{
+ CRYP_CR = (CRYP_CR & ~CRYP_CR_DATATYPE) |
+ (datatype << CRYP_CR_DATATYPE_SHIFT);
+}
+
+/**
+ * @brief Set the algoritm for Encryption/decryption
+ *
+ *@param[in] mode enum crypto_mode Mode of execution
+ */
+void crypto_set_algorithm(enum crypto_mode mode)
+{
+ mode &= ~CRYP_CR_ALGOMODE_MASK;
+
+ if ((mode == DECRYPT_AES_ECB) || (mode == DECRYPT_AES_CBC)) {
+ /* Unroll keys for the AES encoder for the user automatically */
+
+ CRYP_CR = (CRYP_CR & ~CRYP_CR_ALGOMODE_MASK) |
+ CRYP_CR_ALGOMODE_AES_PREP;
+
+ crypto_start();
+ crypto_wait_busy();
+ /* module switches to DISABLE automatically */
+ }
+ /* set algo mode */
+ CRYP_CR = (CRYP_CR & ~CRYP_CR_ALGOMODE_MASK) | mode;
+
+ /* flush buffers */
+ CRYP_CR |= CRYP_CR_FFLUSH;
+}
+
+/**
+ * @brief Enable the cryptographic controller and start processing
+ */
+void crypto_start(void)
+{
+ CRYP_CR |= CRYP_CR_CRYPEN;
+}
+
+/**
+ * @brief Disable the cryptographic controller and stop processing
+ */
+
+void crypto_stop(void)
+{
+ CRYP_CR &= ~CRYP_CR_CRYPEN;
+}
+
+/**
+ * @brief Start of encryption or decryption on data buffers
+ *
+ * This blocking method transfers input buffer of specified length to the
+ * cryptographic coprocessor, and instructs him to begin of ciphering or
+ * deciphering. It waits for data to be ready, and then fills the processed
+ * data to output buffer.
+ *
+ * @param[in] inp uint32_t* Input array to crypt/decrypt.
+ * @param[in] outp uint32_t* Output array with crypted/encrypted data.
+ * @param[in] length uint32_t Length of the arrays
+ *
+ * @returns uint32_t Number of written words
+ */
+uint32_t crypto_process_block(uint32_t *inp, uint32_t *outp, uint32_t length)
+{
+ uint32_t rd = 0, wr = 0;
+
+ /* Transfer the data */
+ while (rd != length) {
+ if ((wr < length) && (CRYP_SR & CRYP_SR_IFNF)) {
+ CRYP_DIN = *inp++;
+ wr++;
+ }
+
+ if (CRYP_SR & CRYP_SR_OFNE) {
+ *outp++ = CRYP_DOUT;
+ rd++;
+ }
+ }
+
+ /* Wait to finish - Not needed ? */
+ crypto_wait_busy();
+
+ return wr;
+}
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/common/dac_common_all.c b/libopencm3/lib/stm32/common/dac_common_all.c
new file mode 100644
index 0000000..a8a0daf
--- /dev/null
+++ b/libopencm3/lib/stm32/common/dac_common_all.c
@@ -0,0 +1,503 @@
+/** @addtogroup dac_file
+
+@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies ksarkies@internode.on.net
+
+This library supports the Digital to Analog Conversion System in the
+STM32F series of ARM Cortex Microcontrollers by ST Microelectronics.
+
+The DAC is present only in a limited set of devices, notably some
+of the connection line, high density and XL devices.
+
+Two DAC channels are available, however unlike the ADC channels these
+are separate DAC devices controlled by the same register block.
+
+The DAC is on APB1. Its clock must be enabled in RCC and depending on
+specific family, the GPIO
+ports set to alternate function output before it can be used.
+On most families, the GPIO pins should be configured to Analog IN to
+avoid parasitic consumption.
+The digital output driver is disabled so the output driver mode
+(push-pull/open drain) is arbitrary.
+
+The DAC has a holding (buffer) register and an output register from
+which the analog output is derived. The holding register must be
+loaded first. If triggering is enabled the output register is loaded
+from the holding register after a trigger occurs. If triggering is
+not enabled the holding register contents are transferred directly
+to the output register.
+
+@note To avoid nonlinearities, do not allow outputs to range close
+to zero or V_analog.
+
+@section dac_api_dual Dual Channel Conversion
+
+There are dual modes in which both DACs are used to output data
+simultaneously or independently on both channels. The data must be
+presented according to the formats described in the datasheets. A
+convenience function @ref dac_load_data_buffer_dual is provided
+for software controlled use.
+
+A variety of modes are available depending on whether independent
+or simultaneous output is desired, and whether waveforms are to be
+superimposed. Refer to the datasheets.
+
+If DMA is used, only enable it for one of the channels. The DMA
+requests will then serve data in dual format to the data register
+dedicated to dual mode. The data will then be split and loaded to the
+appropriate DAC following the next trigger. There are three registers
+available, one for each of the formats: 12 bit right-aligned, 12 bit
+left-aligned and 8 bit right-aligned. The desired format is determined
+by specifying the appropriate register to the DMA controller.
+
+@section dac_api_basic_ex Basic DAC handling API.
+
+Set the DAC's GPIO port to Analog IN. Enable the
+DAC clock. Enable the DAC, set a trigger source and load the buffer
+with the first value. After the DAC is triggered, load the buffer with
+the next value. This example uses software triggering and added noise.
+The trigger and further buffer load calls are made when data is to be
+sent out.
+
+@code
+ gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
+ GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO4);
+ rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_DACEN);
+ dac_disable(CHANNEL_1);
+ dac_set_waveform_characteristics(DAC_CR_MAMP1_8);
+ dac_set_waveform_generation(DAC_CR_WAVE1_NOISE);
+ dac_enable(CHANNEL_1);
+ dac_set_trigger_source(DAC_CR_TSEL1_SW);
+ dac_load_data_buffer_single(0, RIGHT12, CHANNEL_1);
+ ....
+ dac_software_trigger(CHANNEL_1);
+ dac_load_data_buffer_single(value, RIGHT12, CHANNEL_1);
+@endcode
+
+@section dac_api_dma_ex Simultaneous Dual DAC with DMA.
+
+This example in part sets up the DAC channel 1 DMA (DMA2 channel 3) to read
+16 bit data from memory into the right-aligned 8 bit dual register DAC_DHR8RD.
+Both DAC channels are enabled, and both triggers are set to the same timer
+2 input as required for simultaneous operation. DMA is enabled for DAC channel
+1 only to ensure that only one DMA request is generated.
+
+@code
+ dma_set_memory_size(DMA2,DMA_CHANNEL3,DMA_CCR_MSIZE_16BIT);
+ dma_set_peripheral_size(DMA2,DMA_CHANNEL3,DMA_CCR_PSIZE_16BIT);
+ dma_set_read_from_memory(DMA2,DMA_CHANNEL3);
+ dma_set_peripheral_address(DMA2,DMA_CHANNEL3,(uint32_t) &DAC_DHR8RD);
+ dma_enable_channel(DMA2,DMA_CHANNEL3);
+ ...
+ dac_trigger_enable(CHANNEL_D);
+ dac_set_trigger_source(DAC_CR_TSEL1_T2 | DAC_CR_TSEL2_T2);
+ dac_dma_enable(CHANNEL_1);
+ dac_enable(CHANNEL_D);
+@endcode
+
+LGPL License Terms @ref lgpl_license
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Ken Sarkies
+ *
+ * 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/dac.h>
+
+#define MASK8 0xFF
+#define MASK12 0xFFF
+
+/*---------------------------------------------------------------------------*/
+/** @brief DAC Channel Enable.
+
+Enable a digital to analog converter channel. After setting this enable, the
+DAC requires a t<sub>wakeup</sub> time typically around 10 microseconds before
+it actually wakes up.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_enable(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR |= DAC_CR_EN1;
+ break;
+ case CHANNEL_2:
+ DAC_CR |= DAC_CR_EN2;
+ break;
+ case CHANNEL_D:
+ DAC_CR |= (DAC_CR_EN1 | DAC_CR_EN2);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DAC Channel Disable.
+
+Disable a digital to analog converter channel.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_disable(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR &= ~DAC_CR_EN1;
+ break;
+ case CHANNEL_2:
+ DAC_CR &= ~DAC_CR_EN2;
+ break;
+ case CHANNEL_D:
+ DAC_CR &= ~(DAC_CR_EN1 | DAC_CR_EN2);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DAC Channel Output Buffer Enable.
+
+Enable a digital to analog converter channel output drive buffer. This is an
+optional amplifying buffer that provides additional drive for the output
+signal. The buffer is enabled by default after a reset and needs to be
+explicitly disabled if required.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_buffer_enable(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR &= ~DAC_CR_BOFF1;
+ break;
+ case CHANNEL_2:
+ DAC_CR &= ~DAC_CR_BOFF2;
+ break;
+ case CHANNEL_D:
+ DAC_CR &= ~(DAC_CR_BOFF1 | DAC_CR_BOFF2);
+ break;
+ }
+}
+/*---------------------------------------------------------------------------*/
+/** @brief DAC Channel Output Buffer Disable.
+
+Disable a digital to analog converter channel output drive buffer. Disabling
+this will reduce power consumption slightly and will increase the output
+impedance of the DAC. The buffers are enabled by default after a reset.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_buffer_disable(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR |= DAC_CR_BOFF1;
+ break;
+ case CHANNEL_2:
+ DAC_CR |= DAC_CR_BOFF2;
+ break;
+ case CHANNEL_D:
+ DAC_CR |= (DAC_CR_BOFF1 | DAC_CR_BOFF2);
+ break;
+ }
+}
+/*---------------------------------------------------------------------------*/
+/** @brief DAC Channel DMA Enable.
+
+Enable a digital to analog converter channel DMA mode (connected to DMA2 channel
+3 for DAC channel 1 and DMA2 channel 4 for DAC channel 2). A DMA request is
+generated following an external trigger.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_dma_enable(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR |= DAC_CR_DMAEN1;
+ break;
+ case CHANNEL_2:
+ DAC_CR |= DAC_CR_DMAEN2;
+ break;
+ case CHANNEL_D:
+ DAC_CR |= (DAC_CR_DMAEN1 | DAC_CR_DMAEN2);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DAC Channel DMA Disable.
+
+Disable a digital to analog converter channel DMA mode.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_dma_disable(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR &= ~DAC_CR_DMAEN1;
+ break;
+ case CHANNEL_2:
+ DAC_CR &= ~DAC_CR_DMAEN2;
+ break;
+ case CHANNEL_D:
+ DAC_CR &= ~(DAC_CR_DMAEN1 | DAC_CR_DMAEN2);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DAC Channel Trigger Enable.
+
+Enable a digital to analog converter channel external trigger mode. This allows
+an external trigger to initiate register transfers from the buffer register to
+the DAC output register, followed by a DMA transfer to the buffer register if
+DMA is enabled. The trigger source must also be selected.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_trigger_enable(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR |= DAC_CR_TEN1;
+ break;
+ case CHANNEL_2:
+ DAC_CR |= DAC_CR_TEN2;
+ break;
+ case CHANNEL_D:
+ DAC_CR |= (DAC_CR_TEN1 | DAC_CR_TEN2);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DAC Channel Trigger Disable.
+
+Disable a digital to analog converter channel external trigger.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_trigger_disable(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR &= ~DAC_CR_TEN1;
+ break;
+ case CHANNEL_2:
+ DAC_CR &= ~DAC_CR_TEN2;
+ break;
+ case CHANNEL_D:
+ DAC_CR &= ~(DAC_CR_TEN1 | DAC_CR_TEN2);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set DAC Channel Trigger Source.
+
+Sets the digital to analog converter trigger source, which can be taken from
+various timers, an external trigger or a software trigger.
+
+@param[in] dac_trig_src uint32_t. Taken from @ref dac_trig2_sel or @ref
+dac_trig1_sel or a logical OR of one of each of these to set both channels
+simultaneously.
+*/
+
+void dac_set_trigger_source(uint32_t dac_trig_src)
+{
+ DAC_CR |= dac_trig_src;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable and Set DAC Channel Waveform Generation.
+
+Enable the digital to analog converter waveform generation as either
+pseudo-random noise or triangular wave. These signals are superimposed on
+existing output values in the DAC output registers.
+
+@note The DAC trigger must be enabled for this to work.
+
+@param[in] dac_wave_ens uint32_t. Taken from @ref dac_wave1_en or @ref
+dac_wave2_en or a logical OR of one of each of these to set both channels
+simultaneously.
+*/
+
+void dac_set_waveform_generation(uint32_t dac_wave_ens)
+{
+ DAC_CR |= dac_wave_ens;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable DAC Channel Waveform Generation.
+
+Disable a digital to analog converter channel superimposed waveform generation.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_disable_waveform_generation(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_CR &= ~DAC_CR_WAVE1_DIS;
+ break;
+ case CHANNEL_2:
+ DAC_CR &= ~DAC_CR_WAVE2_DIS;
+ break;
+ case CHANNEL_D:
+ DAC_CR &= ~(DAC_CR_WAVE1_DIS | DAC_CR_WAVE2_DIS);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set DAC Channel LFSR Mask or Triangle Wave Amplitude.
+
+Sets the digital to analog converter superimposed waveform generation
+characteristics. @li If the noise generation mode is set, this sets the length
+of the PRBS sequence and hence the amplitude of the output noise signal.
+Default setting is length 1. @li If the triangle wave generation mode is set,
+this sets the amplitude of the output signal as 2^(n)-1 where n is the
+parameter value. Default setting is 1.
+
+@note High amplitude levels of these waveforms can overload the DAC and distort
+the signal output.
+@note This must be called before enabling the DAC as the settings will then
+become read-only.
+@note The DAC trigger must be enabled for this to work.
+
+@param[in] dac_mamp uint32_t. Taken from @ref dac_mamp2 or @ref dac_mamp1 or a
+logical OR of one of each of these to set both channels simultaneously.
+*/
+
+void dac_set_waveform_characteristics(uint32_t dac_mamp)
+{
+ DAC_CR |= dac_mamp;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Load DAC Data Register.
+
+Loads the appropriate digital to analog converter data register with 12 or 8 bit
+data to be converted on a channel. The data can be aligned as follows:
+@li right-aligned 8 bit data in bits 0-7
+@li right-aligned 12 bit data in bits 0-11
+@li left aligned 12 bit data in bits 4-15
+
+@param[in] dac_data uint16_t with appropriate alignment.
+@param[in] dac_data_format enum ::data_align. Alignment and size.
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_load_data_buffer_single(uint16_t dac_data, data_align dac_data_format,
+ data_channel dac_channel)
+{
+ if (dac_channel == CHANNEL_1) {
+ switch (dac_data_format) {
+ case RIGHT8:
+ DAC_DHR8R1 = dac_data;
+ break;
+ case RIGHT12:
+ DAC_DHR12R1 = dac_data;
+ break;
+ case LEFT12:
+ DAC_DHR12L1 = dac_data;
+ break;
+ }
+ } else if (dac_channel == CHANNEL_2) {
+ switch (dac_data_format) {
+ case RIGHT8:
+ DAC_DHR8R2 = dac_data;
+ break;
+ case RIGHT12:
+ DAC_DHR12R2 = dac_data;
+ break;
+ case LEFT12:
+ DAC_DHR12L2 = dac_data;
+ break;
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Load DAC Dual Data Register.
+
+Loads the appropriate digital to analog converter dual data register with 12 or
+8 bit data to be converted for both channels. This allows high bandwidth
+simultaneous or independent analog output. The data in both channels are aligned
+identically.
+
+@param[in] dac_data1 uint16_t for channel 1 with appropriate alignment.
+@param[in] dac_data2 uint16_t for channel 2 with appropriate alignment.
+@param[in] dac_data_format enum ::data_align. Right or left aligned, and 8 or
+12 bit.
+*/
+
+void dac_load_data_buffer_dual(uint16_t dac_data1, uint16_t dac_data2,
+ data_align dac_data_format)
+{
+ switch (dac_data_format) {
+ case RIGHT8:
+ DAC_DHR8RD = ((dac_data1 & MASK8) | ((dac_data2 & MASK8) << 8));
+ break;
+ case RIGHT12:
+ DAC_DHR12RD = ((dac_data1 & MASK12) |
+ ((dac_data2 & MASK12) << 16));
+ break;
+ case LEFT12:
+ DAC_DHR12LD = ((dac_data1 & MASK12) |
+ ((dac_data2 & MASK12) << 16));
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Trigger the DAC by a Software Trigger.
+
+If the trigger source is set to be a software trigger, cause a trigger to occur.
+The trigger is cleared by hardware after conversion.
+
+@param[in] dac_channel enum ::data_channel.
+*/
+
+void dac_software_trigger(data_channel dac_channel)
+{
+ switch (dac_channel) {
+ case CHANNEL_1:
+ DAC_SWTRIGR |= DAC_SWTRIGR_SWTRIG1;
+ break;
+ case CHANNEL_2:
+ DAC_SWTRIGR |= DAC_SWTRIGR_SWTRIG2;
+ break;
+ case CHANNEL_D:
+ DAC_SWTRIGR |= (DAC_SWTRIGR_SWTRIG1 | DAC_SWTRIGR_SWTRIG2);
+ break;
+ }
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/dma_common_f24.c b/libopencm3/lib/stm32/common/dma_common_f24.c
new file mode 100644
index 0000000..6b65563
--- /dev/null
+++ b/libopencm3/lib/stm32/common/dma_common_f24.c
@@ -0,0 +1,794 @@
+/** @addtogroup dma_file
+
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+This library supports the DMA Control System in the STM32F2 and STM32F4
+series of ARM Cortex Microcontrollers by ST Microelectronics.
+
+Up to two DMA controllers are supported each with 8 streams, and each stream
+having up to 8 channels hardware dedicated to various peripheral DMA signals.
+
+DMA transfers can be configured to occur between peripheral and memory in
+either direction, and memory to memory. Peripheral to peripheral transfer
+is not supported. Circular mode transfers are also supported in transfers
+involving a peripheral. An arbiter is provided to resolve priority DMA
+requests. Transfers can be made with 8, 16 or 32 bit words.
+
+Each stream has access to a 4 word deep FIFO and can use double buffering
+by means of two memory pointers. When using the FIFO it is possible to
+configure transfers to occur in indivisible bursts.
+
+It is also possible to select a peripheral instead of the DMA controller to
+control the flow of data. This limits the functionality but is useful when the
+number of transfers is unknown.
+
+LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * 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/dma.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Reset
+
+The specified stream is disabled and configuration registers are cleared.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_stream_reset(uint32_t dma, uint8_t stream)
+{
+/* Disable stream (must be done before register is otherwise changed). */
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_EN;
+/* Reset all config bits. */
+ DMA_SCR(dma, stream) = 0;
+/* Reset data transfer number. */
+ DMA_SNDTR(dma, stream) = 0;
+/* Reset peripheral and memory addresses. */
+ DMA_SPAR(dma, stream) = 0;
+ DMA_SM0AR(dma, stream) = 0;
+ DMA_SM1AR(dma, stream) = 0;
+/* This is the default setting */
+ DMA_SFCR(dma, stream) = 0x21;
+/* Reset all stream interrupt flags using the interrupt flag clear register. */
+ uint32_t mask = DMA_ISR_MASK(stream);
+ if (stream < 4) {
+ DMA_LIFCR(dma) |= mask;
+ } else {
+ DMA_HIFCR(dma) |= mask;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Clear Interrupt Flag
+
+The interrupt flag for the stream is cleared. More than one interrupt for the
+same stream may be cleared by using the bitwise OR of the interrupt flags.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] interrupts unsigned int32. Bitwise OR of interrupt numbers: @ref
+dma_if_offset
+*/
+
+void dma_clear_interrupt_flags(uint32_t dma, uint8_t stream,
+ uint32_t interrupts)
+{
+ /* Get offset to interrupt flag location in stream field */
+ uint32_t flags = (interrupts << DMA_ISR_OFFSET(stream));
+ /* First four streams are in low register. Flag clear must be set then
+ * reset.
+ */
+ if (stream < 4) {
+ DMA_LIFCR(dma) = flags;
+ } else {
+ DMA_HIFCR(dma) = flags;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Read Interrupt Flag
+
+The interrupt flag for the stream is returned.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] interrupt unsigned int32. Interrupt number: @ref dma_if_offset
+@returns bool interrupt flag is set.
+*/
+
+bool dma_get_interrupt_flag(uint32_t dma, uint8_t stream, uint32_t interrupt)
+{
+ /* get offset to interrupt flag location in stream field. Assumes
+ * stream and interrupt parameters are integers.
+ */
+ uint32_t flag = (interrupt << DMA_ISR_OFFSET(stream));
+ /* First four streams are in low register */
+ if (stream < 4) {
+ return ((DMA_LISR(dma) & flag) > 0);
+ } else {
+ return ((DMA_HISR(dma) & flag) > 0);
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable Transfer Direction
+
+Set peripheral to memory, memory to peripheral or memory to memory. If memory
+to memory mode is selected, circular mode and double buffer modes are disabled.
+Ensure that these modes are not enabled at a later time.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] direction unsigned int32. Data transfer direction @ref dma_st_dir
+*/
+
+void dma_set_transfer_mode(uint32_t dma, uint8_t stream, uint32_t direction)
+{
+ uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_DIR_MASK);
+ /* Disable circular and double buffer modes if memory to memory
+ * transfers are in effect. (Direct Mode is automatically disabled by
+ * hardware)
+ */
+ if (direction == DMA_SxCR_DIR_MEM_TO_MEM) {
+ reg32 &= ~(DMA_SxCR_CIRC | DMA_SxCR_DBM);
+ }
+
+ DMA_SCR(dma, stream) = (reg32 | direction);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set Priority
+
+Stream Priority has four levels: low to very high. This has precedence over the
+hardware priority. In the event of equal software priority the lower numbered
+stream has priority.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] prio unsigned int32. Priority level @ref dma_st_pri.
+*/
+
+void dma_set_priority(uint32_t dma, uint8_t stream, uint32_t prio)
+{
+ DMA_SCR(dma, stream) &= ~(DMA_SxCR_PL_MASK);
+ DMA_SCR(dma, stream) |= prio;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set Memory Word Width
+
+Set the memory word width 8 bits, 16 bits, or 32 bits. Refer to datasheet for
+alignment information if the source and destination widths do not match.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] mem_size unsigned int32. Memory word width @ref dma_st_memwidth.
+*/
+
+void dma_set_memory_size(uint32_t dma, uint8_t stream, uint32_t mem_size)
+{
+ DMA_SCR(dma, stream) &= ~(DMA_SxCR_MSIZE_MASK);
+ DMA_SCR(dma, stream) |= mem_size;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set Peripheral Word Width
+
+Set the peripheral word width 8 bits, 16 bits, or 32 bits. Refer to datasheet
+for alignment information if the source and destination widths do not match, or
+if the peripheral does not support byte or half-word writes.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] peripheral_size unsigned int32. Peripheral word width @ref
+dma_st_perwidth.
+*/
+
+void dma_set_peripheral_size(uint32_t dma, uint8_t stream,
+ uint32_t peripheral_size)
+{
+ DMA_SCR(dma, stream) &= ~(DMA_SxCR_PSIZE_MASK);
+ DMA_SCR(dma, stream) |= peripheral_size;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable Memory Increment after Transfer
+
+Following each transfer the current memory address is incremented by
+1, 2 or 4 depending on the data size set in @ref dma_set_memory_size. The
+value held by the base memory address register is unchanged.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_memory_increment_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) |= DMA_SxCR_MINC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Disable Memory Increment after Transfer
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_memory_increment_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_MINC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Variable Sized Peripheral Increment after Transfer
+
+Following each transfer the current peripheral address is incremented by
+1, 2 or 4 depending on the data size set in @ref dma_set_peripheral_size. The
+value held by the base peripheral address register is unchanged.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_peripheral_increment_mode(uint32_t dma, uint8_t stream)
+{
+ uint32_t reg32 = (DMA_SCR(dma, stream) | DMA_SxCR_PINC);
+ DMA_SCR(dma, stream) = (reg32 & ~DMA_SxCR_PINCOS);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Disable Peripheral Increment after Transfer
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_peripheral_increment_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_PINC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Fixed Sized Peripheral Increment after Transfer
+
+Following each transfer the current peripheral address is incremented by
+4 regardless of the data size. The value held by the base peripheral address
+register is unchanged.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_fixed_peripheral_increment_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) |= (DMA_SxCR_PINC | DMA_SxCR_PINCOS);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable Memory Circular Mode
+
+After the number of bytes/words to be transferred has been completed, the
+original transfer block size, memory and peripheral base addresses are
+reloaded and the process repeats.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@note This cannot be used with memory to memory mode. It is disabled
+automatically if the peripheral is selected as the flow controller.
+It is enabled automatically if double buffered mode is selected.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_circular_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) |= DMA_SxCR_CIRC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Channel Select
+
+Associate an input channel to the stream. Not every channel is allocated to a
+hardware DMA request signal. The allocations for each stream are given in the
+STM32F4 Reference Manual.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] channel unsigned int8. Channel selection @ref dma_ch_sel
+*/
+
+void dma_channel_select(uint32_t dma, uint8_t stream, uint32_t channel)
+{
+ DMA_SCR(dma, stream) |= channel;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set Memory Burst Configuration
+
+Set the memory burst type to none, 4 8 or 16 word length. This is forced to none
+if direct mode is used.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] burst unsigned int8. Memory Burst selection @ref dma_mburst
+*/
+
+void dma_set_memory_burst(uint32_t dma, uint8_t stream, uint32_t burst)
+{
+ uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_MBURST_MASK);
+ DMA_SCR(dma, stream) = (reg32 | burst);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set Peripheral Burst Configuration
+
+Set the memory burst type to none, 4 8 or 16 word length. This is forced to none
+if direct mode is used.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] burst unsigned int8. Peripheral Burst selection @ref dma_pburst
+*/
+
+void dma_set_peripheral_burst(uint32_t dma, uint8_t stream, uint32_t burst)
+{
+ uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_PBURST_MASK);
+ DMA_SCR(dma, stream) = (reg32 | burst);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set Initial Target Memory
+
+In double buffered mode, set the target memory (M0 or M1) to be used for the
+first transfer.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] memory unsigned int8. Initial memory pointer to use: 0 or 1
+*/
+
+void dma_set_initial_target(uint32_t dma, uint8_t stream, uint8_t memory)
+{
+ uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_CT);
+ if (memory == 1) {
+ reg32 |= DMA_SxCR_CT;
+ }
+
+ DMA_SCR(dma, stream) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Read Current Memory Target
+
+In double buffer mode, return the current memory target (M0 or M1). It is
+possible to update the memory pointer in the register that is <b> not </b>
+currently in use. An attempt to change the register currently in use will cause
+the stream to be disabled and the transfer error flag to be set.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@returns unsigned int8. Memory buffer in use: 0 or 1
+*/
+
+uint8_t dma_get_target(uint32_t dma, uint8_t stream)
+{
+ if (DMA_SCR(dma, stream) & DMA_SxCR_CT) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable Double Buffer Mode
+
+Double buffer mode is used for memory to/from peripheral transfers only, and in
+circular mode which is automatically enabled. Two memory buffers must be
+established with pointers stored in the memory pointer registers.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@note This cannot be used with memory to memory mode.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_double_buffer_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) |= DMA_SxCR_DBM;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Disable Double Buffer Mode
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_double_buffer_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_DBM;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set Peripheral Flow Control
+
+Set the peripheral to control DMA flow. Useful when the number of transfers is
+unknown. This is forced off when memory to memory mode is selected.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_set_peripheral_flow_control(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) |= DMA_SxCR_PFCTRL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set DMA Flow Control
+
+Set the DMA controller to control DMA flow. This is the default.
+
+Ensure that the stream is disabled otherwise the setting will not be changed.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_set_dma_flow_control(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_PFCTRL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable Interrupt on Transfer Error
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_transfer_error_interrupt(uint32_t dma, uint8_t stream)
+{
+ dma_clear_interrupt_flags(dma, stream, DMA_TEIF);
+ DMA_SCR(dma, stream) |= DMA_SxCR_TEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Disable Interrupt on Transfer Error
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_transfer_error_interrupt(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_TEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable Interrupt on Transfer Half Complete
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_half_transfer_interrupt(uint32_t dma, uint8_t stream)
+{
+ dma_clear_interrupt_flags(dma, stream, DMA_HTIF);
+ DMA_SCR(dma, stream) |= DMA_SxCR_HTIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Disable Interrupt on Transfer Half Complete
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_half_transfer_interrupt(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_HTIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable Interrupt on Transfer Complete
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_transfer_complete_interrupt(uint32_t dma, uint8_t stream)
+{
+ dma_clear_interrupt_flags(dma, stream, DMA_TCIF);
+ DMA_SCR(dma, stream) |= DMA_SxCR_TCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Disable Interrupt on Transfer Complete
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_transfer_complete_interrupt(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_TCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable Interrupt on Direct Mode Error
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_direct_mode_error_interrupt(uint32_t dma, uint8_t stream)
+{
+ dma_clear_interrupt_flags(dma, stream, DMA_DMEIF);
+ DMA_SCR(dma, stream) |= DMA_SxCR_DMEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Disable Interrupt on Direct Mode Error
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_direct_mode_error_interrupt(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_DMEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Enable Interrupt on FIFO Error
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_fifo_error_interrupt(uint32_t dma, uint8_t stream)
+{
+ dma_clear_interrupt_flags(dma, stream, DMA_FEIF);
+ DMA_SFCR(dma, stream) |= DMA_SxFCR_FEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Disable Interrupt on FIFO Error
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_fifo_error_interrupt(uint32_t dma, uint8_t stream)
+{
+ DMA_SFCR(dma, stream) &= ~DMA_SxFCR_FEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Get FIFO Status
+
+Status of FIFO (empty. full or partial filled states) is returned. This has no
+meaning if direct mode is enabled (as the FIFO is not used).
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@returns uint32_t FIFO Status @ref dma_fifo_status
+*/
+
+uint32_t dma_fifo_status(uint32_t dma, uint8_t stream)
+{
+ return DMA_SFCR(dma, stream) & DMA_SxFCR_FS_MASK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Enable Direct Mode
+
+Direct mode is the default. Data is transferred as soon as a DMA request is
+received. The FIFO is not used. This must not be set when memory to memory
+mode is selected.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_direct_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SFCR(dma, stream) &= ~DMA_SxFCR_DMDIS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Enable FIFO Mode
+
+Data is transferred via a FIFO.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_fifo_mode(uint32_t dma, uint8_t stream)
+{
+ DMA_SFCR(dma, stream) |= DMA_SxFCR_DMDIS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Set FIFO Threshold
+
+This is the filled level at which data is transferred out of the FIFO to the
+destination.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] threshold unsigned int8. Threshold setting @ref dma_fifo_thresh
+*/
+
+void dma_set_fifo_threshold(uint32_t dma, uint8_t stream, uint32_t threshold)
+{
+ uint32_t reg32 = (DMA_SFCR(dma, stream) & ~DMA_SxFCR_FTH_MASK);
+ DMA_SFCR(dma, stream) = (reg32 | threshold);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Enable
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_enable_stream(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) |= DMA_SxCR_EN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Disable
+
+@note The DMA stream registers retain their values when the stream is disabled.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+*/
+
+void dma_disable_stream(uint32_t dma, uint8_t stream)
+{
+ DMA_SCR(dma, stream) &= ~DMA_SxCR_EN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set the Peripheral Address
+
+Set the address of the peripheral register to or from which data is to be
+transferred. Refer to the documentation for the specific peripheral.
+
+@note The DMA stream must be disabled before setting this address. This function
+has no effect if the stream is enabled.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] address unsigned int32. Peripheral Address.
+*/
+
+void dma_set_peripheral_address(uint32_t dma, uint8_t stream, uint32_t address)
+{
+ if (!(DMA_SCR(dma, stream) & DMA_SxCR_EN)) {
+ DMA_SPAR(dma, stream) = (uint32_t *) address;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set the Base Memory Address 0
+
+Set the address pointer to the memory location for DMA transfers. The DMA stream
+must normally be disabled before setting this address, however it is possible
+to change this in double buffer mode when the current target is memory area 1
+(see @ref dma_get_target).
+
+This is the default base memory address used in direct mode.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] address unsigned int32. Memory Initial Address.
+*/
+
+void dma_set_memory_address(uint32_t dma, uint8_t stream, uint32_t address)
+{
+ uint32_t reg32 = DMA_SCR(dma, stream);
+ if (!(reg32 & DMA_SxCR_EN) ||
+ ((reg32 & DMA_SxCR_CT) && (reg32 & DMA_SxCR_DBM))) {
+ DMA_SM0AR(dma, stream) = (uint32_t *) address;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set the Base Memory Address 1
+
+Set the address pointer to the memory location for DMA transfers. The DMA stream
+must normally be disabled before setting this address, however it is possible
+to change this in double buffer mode when the current target is memory area 0
+(see @ref dma_get_target).
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] address unsigned int32. Memory Initial Address.
+*/
+
+void dma_set_memory_address_1(uint32_t dma, uint8_t stream, uint32_t address)
+{
+ uint32_t reg32 = DMA_SCR(dma, stream);
+ if (!(reg32 & DMA_SxCR_EN) ||
+ (!(reg32 & DMA_SxCR_CT) && (reg32 & DMA_SxCR_DBM))) {
+ DMA_SM1AR(dma, stream) = (uint32_t *) address;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Stream Set the Transfer Block Size
+
+@note The DMA stream must be disabled before setting this count value. The count
+is not changed if the stream is enabled.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] stream unsigned int8. Stream number: @ref dma_st_number
+@param[in] number unsigned int16. Number of data words to transfer (65535
+maximum).
+*/
+
+void dma_set_number_of_data(uint32_t dma, uint8_t stream, uint16_t number)
+{
+ DMA_SNDTR(dma, stream) = number;
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/dma_common_l1f013.c b/libopencm3/lib/stm32/common/dma_common_l1f013.c
new file mode 100644
index 0000000..d705964
--- /dev/null
+++ b/libopencm3/lib/stm32/common/dma_common_l1f013.c
@@ -0,0 +1,435 @@
+/** @addtogroup dma_file
+
+@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
+
+This library supports the DMA Control System in the STM32 series of ARM Cortex
+Microcontrollers by ST Microelectronics.
+
+Up to two DMA controllers are supported. 12 DMA channels are allocated 7 to
+the first DMA controller and 5 to the second. Each channel is connected to
+between 3 and 6 hardware peripheral DMA signals in a logical OR arrangement.
+
+DMA transfers can be configured to occur between peripheral and memory in
+any combination including memory to memory. Circular mode transfers are
+also supported in transfers involving a peripheral. An arbiter is provided
+to resolve priority DMA requests. Transfers can be made with 8, 16 or 32 bit
+words.
+
+LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.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/dma.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Reset
+
+The channel is disabled and configuration registers are cleared.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_channel_reset(uint32_t dma, uint8_t channel)
+{
+ /* Disable channel and reset config bits. */
+ DMA_CCR(dma, channel) = 0;
+ /* Reset data transfer number. */
+ DMA_CNDTR(dma, channel) = 0;
+ /* Reset peripheral address. */
+ DMA_CPAR(dma, channel) = 0;
+ /* Reset memory address. */
+ DMA_CMAR(dma, channel) = 0;
+ /* Reset interrupt flags. */
+ DMA_IFCR(dma) |= DMA_IFCR_CIF(channel);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Clear Interrupt Flag
+
+The interrupt flag for the channel is cleared. More than one interrupt for the
+same channel may be cleared by using the logical OR of the interrupt flags.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: @ref dma_ch
+@param[in] interrupts unsigned int32. Logical OR of interrupt numbers: @ref
+dma_if_offset
+*/
+
+void dma_clear_interrupt_flags(uint32_t dma, uint8_t channel,
+ uint32_t interrupts)
+{
+/* Get offset to interrupt flag location in channel field */
+ uint32_t flags = (interrupts << DMA_FLAG_OFFSET(channel));
+ DMA_IFCR(dma) = flags;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Read Interrupt Flag
+
+The interrupt flag for the channel is returned.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: @ref dma_ch
+@param[in] interrupt unsigned int32. Interrupt number: @ref dma_if_offset
+@returns bool interrupt flag is set.
+*/
+
+bool dma_get_interrupt_flag(uint32_t dma, uint8_t channel, uint32_t interrupt)
+{
+/* get offset to interrupt flag location in channel field. */
+ uint32_t flag = (interrupt << DMA_FLAG_OFFSET(channel));
+ return ((DMA_ISR(dma) & flag) > 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Memory to Memory Transfers
+
+Memory to memory transfers do not require a trigger to activate each transfer.
+Transfers begin immediately the channel has been enabled, and proceed without
+intervention.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_enable_mem2mem_mode(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_MEM2MEM;
+ DMA_CCR(dma, channel) &= ~DMA_CCR_CIRC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Set Priority
+
+Channel Priority has four levels: low to very high. This has precedence over the
+hardware priority.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+@param[in] prio unsigned int32. Priority level @ref dma_ch_pri.
+*/
+
+void dma_set_priority(uint32_t dma, uint8_t channel, uint32_t prio)
+{
+ DMA_CCR(dma, channel) &= ~(DMA_CCR_PL_MASK);
+ DMA_CCR(dma, channel) |= prio;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Set Memory Word Width
+
+Set the memory word width 8 bits, 16 bits, or 32 bits. Refer to datasheet for
+alignment information if the source and destination widths do not match.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+@param[in] mem_size unsigned int32. Memory word width @ref dma_ch_memwidth.
+*/
+
+void dma_set_memory_size(uint32_t dma, uint8_t channel, uint32_t mem_size)
+{
+
+ DMA_CCR(dma, channel) &= ~(DMA_CCR_MSIZE_MASK);
+ DMA_CCR(dma, channel) |= mem_size;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Set Peripheral Word Width
+
+Set the peripheral word width 8 bits, 16 bits, or 32 bits. Refer to datasheet
+for alignment information if the source and destination widths do not match, or
+if the peripheral does not support byte or half-word writes.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+@param[in] peripheral_size unsigned int32. Peripheral word width @ref
+dma_ch_perwidth.
+*/
+
+void dma_set_peripheral_size(uint32_t dma, uint8_t channel,
+ uint32_t peripheral_size)
+{
+ DMA_CCR(dma, channel) &= ~(DMA_CCR_PSIZE_MASK);
+ DMA_CCR(dma, channel) |= peripheral_size;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Memory Increment after Transfer
+
+Following each transfer the current memory address is incremented by
+1, 2 or 4 depending on the data size set in @ref dma_set_memory_size. The
+value held by the base memory address register is unchanged.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_enable_memory_increment_mode(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_MINC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Disable Memory Increment after Transfer
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_disable_memory_increment_mode(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) &= ~DMA_CCR_MINC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Peripheral Increment after Transfer
+
+Following each transfer the current peripheral address is incremented by
+1, 2 or 4 depending on the data size set in @ref dma_set_peripheral_size. The
+value held by the base peripheral address register is unchanged.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_enable_peripheral_increment_mode(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_PINC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Disable Peripheral Increment after Transfer
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_disable_peripheral_increment_mode(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) &= ~DMA_CCR_PINC;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Memory Circular Mode
+
+After the number of bytes/words to be transferred has been completed, the
+original transfer block size, memory and peripheral base addresses are
+reloaded and the process repeats.
+
+@note This cannot be used with memory to memory mode, which is explictly
+disabled here.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_enable_circular_mode(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_CIRC;
+ DMA_CCR(dma, channel) &= ~DMA_CCR_MEM2MEM;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Transfers from a Peripheral
+
+The data direction is set to read from a peripheral.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_set_read_from_peripheral(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) &= ~DMA_CCR_DIR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Transfers from Memory
+
+The data direction is set to read from memory.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_set_read_from_memory(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_DIR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Interrupt on Transfer Error
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_enable_transfer_error_interrupt(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_TEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Disable Interrupt on Transfer Error
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_disable_transfer_error_interrupt(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) &= ~DMA_CCR_TEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Interrupt on Transfer Half Complete
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_enable_half_transfer_interrupt(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_HTIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Disable Interrupt on Transfer Half Complete
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_disable_half_transfer_interrupt(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) &= ~DMA_CCR_HTIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable Interrupt on Transfer Complete
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_enable_transfer_complete_interrupt(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_TCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Disable Interrupt on Transfer Complete
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_disable_transfer_complete_interrupt(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) &= ~DMA_CCR_TCIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Enable
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_enable_channel(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) |= DMA_CCR_EN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Disable
+
+@note The DMA channel registers retain their values when the channel is
+disabled.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+*/
+
+void dma_disable_channel(uint32_t dma, uint8_t channel)
+{
+ DMA_CCR(dma, channel) &= ~DMA_CCR_EN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Set the Peripheral Address
+
+Set the address of the peripheral register to or from which data is to be
+transferred. Refer to the documentation for the specific peripheral.
+
+@note The DMA channel must be disabled before setting this address. This
+function has no effect if the channel is enabled.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+@param[in] address unsigned int32. Peripheral Address.
+*/
+
+void dma_set_peripheral_address(uint32_t dma, uint8_t channel, uint32_t address)
+{
+ if (!(DMA_CCR(dma, channel) & DMA_CCR_EN)) {
+ DMA_CPAR(dma, channel) = (uint32_t) address;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Set the Base Memory Address
+
+@note The DMA channel must be disabled before setting this address. This
+function has no effect if the channel is enabled.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+@param[in] address unsigned int32. Memory Initial Address.
+*/
+
+void dma_set_memory_address(uint32_t dma, uint8_t channel, uint32_t address)
+{
+ if (!(DMA_CCR(dma, channel) & DMA_CCR_EN)) {
+ DMA_CMAR(dma, channel) = (uint32_t) address;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief DMA Channel Set the Transfer Block Size
+
+@note The DMA channel must be disabled before setting this count value. The
+count is not changed if the channel is enabled.
+
+@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
+@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
+@param[in] number unsigned int16. Number of data words to transfer (65535
+maximum).
+*/
+
+void dma_set_number_of_data(uint32_t dma, uint8_t channel, uint16_t number)
+{
+ DMA_CNDTR(dma, channel) = number;
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/exti_common_all.c b/libopencm3/lib/stm32/common/exti_common_all.c
new file mode 100644
index 0000000..f7b0d0c
--- /dev/null
+++ b/libopencm3/lib/stm32/common/exti_common_all.c
@@ -0,0 +1,154 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
+ * 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/>.
+ *
+ * This provides the code for the "next gen" EXTI block provided in F2/F4/L1
+ * devices. (differences only in the source selection)
+ */
+/**@{*/
+
+
+#include <libopencm3/stm32/exti.h>
+#include <libopencm3/stm32/gpio.h>
+#if !defined(AFIO_BASE)
+# include <libopencm3/stm32/syscfg.h>
+#endif
+
+void exti_set_trigger(uint32_t extis, enum exti_trigger_type trig)
+{
+ switch (trig) {
+ case EXTI_TRIGGER_RISING:
+ EXTI_RTSR |= extis;
+ EXTI_FTSR &= ~extis;
+ break;
+ case EXTI_TRIGGER_FALLING:
+ EXTI_RTSR &= ~extis;
+ EXTI_FTSR |= extis;
+ break;
+ case EXTI_TRIGGER_BOTH:
+ EXTI_RTSR |= extis;
+ EXTI_FTSR |= extis;
+ break;
+ }
+}
+
+void exti_enable_request(uint32_t extis)
+{
+ /* Enable interrupts. */
+ EXTI_IMR |= extis;
+
+ /* Enable events. */
+ EXTI_EMR |= extis;
+}
+
+void exti_disable_request(uint32_t extis)
+{
+ /* Disable interrupts. */
+ EXTI_IMR &= ~extis;
+
+ /* Disable events. */
+ EXTI_EMR &= ~extis;
+}
+
+/*
+ * Reset the interrupt request by writing a 1 to the corresponding
+ * pending bit register.
+ */
+void exti_reset_request(uint32_t extis)
+{
+ EXTI_PR = extis;
+}
+
+/*
+ * Check the flag of a given EXTI interrupt.
+ * */
+uint32_t exti_get_flag_status(uint32_t exti)
+{
+ return EXTI_PR & exti;
+}
+
+/*
+ * Remap an external interrupt line to the corresponding pin on the
+ * specified GPIO port.
+ *
+ * TODO: This could be rewritten in fewer lines of code.
+ */
+void exti_select_source(uint32_t exti, uint32_t gpioport)
+{
+ uint32_t line;
+ for (line = 0; line < 16; line++) {
+ if (!(exti & (1 << line))) {
+ continue;
+ }
+
+ uint32_t bits = 0, mask = 0x0F;
+
+ switch (gpioport) {
+ case GPIOA:
+ bits = 0;
+ break;
+ case GPIOB:
+ bits = 1;
+ break;
+ case GPIOC:
+ bits = 2;
+ break;
+ case GPIOD:
+ bits = 3;
+ break;
+#if defined(GPIOE) && defined(GPIO_PORT_E_BASE)
+ case GPIOE:
+ bits = 4;
+ break;
+#endif
+#if defined(GPIOF) && defined(GPIO_PORT_F_BASE)
+ case GPIOF:
+ bits = 5;
+ break;
+#endif
+#if defined(GPIOG) && defined(GPIO_PORT_G_BASE)
+ case GPIOG:
+ bits = 6;
+ break;
+#endif
+#if defined(GPIOH) && defined(GPIO_PORT_H_BASE)
+ case GPIOH:
+ bits = 7;
+ break;
+#endif
+#if defined(GPIOI) && defined(GPIO_PORT_I_BASE)
+ case GPIOI:
+ bits = 8;
+ break;
+#endif
+ }
+
+ uint8_t shift = (uint8_t)(4 * (line % 4));
+ uint32_t reg = line / 4;
+ bits <<= shift;
+ mask <<= shift;
+
+#if defined(AFIO_BASE)
+ AFIO_EXTICR(reg) = (AFIO_EXTICR(reg) & ~mask) | bits;
+#else
+ SYSCFG_EXTICR(reg) = (SYSCFG_EXTICR(reg) & ~mask) | bits;
+#endif
+ };
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/flash_common_f01.c b/libopencm3/lib/stm32/common/flash_common_f01.c
new file mode 100644
index 0000000..65f64bd
--- /dev/null
+++ b/libopencm3/lib/stm32/common/flash_common_f01.c
@@ -0,0 +1,235 @@
+/** @addtogroup flash_file
+ *
+ */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2014 Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * 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 the FLASH Prefetch Buffer
+
+This buffer is used for instruction fetches and is enabled by default after
+reset.
+
+Note carefully the clock restrictions under which the prefetch buffer may be
+enabled or disabled. Changes are normally made while the clock is running in
+the power-on low frequency mode before being set to a higher speed mode.
+See the reference manual for details.
+*/
+
+void flash_prefetch_buffer_enable(void)
+{
+ FLASH_ACR |= FLASH_ACR_PRFTBE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable the FLASH Prefetch Buffer
+
+Note carefully the clock restrictions under which the prefetch buffer may be
+set to disabled. See the reference manual for details.
+*/
+
+void flash_prefetch_buffer_disable(void)
+{
+ FLASH_ACR &= ~FLASH_ACR_PRFTBE;
+}
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Number of Wait States
+
+Used to match the system clock to the FLASH memory access time. See the
+reference manual for more information on clock speed ranges for each wait state.
+The latency must be changed to the appropriate value <b>before</b> any increase
+in clock speed, or <b>after</b> any decrease in clock speed.
+
+@param[in] uint32_t ws: values from @ref flash_latency.
+*/
+
+void flash_set_ws(uint32_t ws)
+{
+ FLASH_ACR = (FLASH_ACR & ~FLASH_ACR_LATENCY) | ws;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Unlock the Flash Program and Erase Controller
+
+This enables write access to the Flash memory. It is locked by default on
+reset.
+*/
+
+void flash_unlock(void)
+{
+ /* Clear the unlock state. */
+ FLASH_CR |= FLASH_CR_LOCK;
+
+ /* Authorize the FPEC access. */
+ FLASH_KEYR = FLASH_KEYR_KEY1;
+ FLASH_KEYR = FLASH_KEYR_KEY2;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Lock the Flash Program and Erase Controller
+
+Used to prevent spurious writes to FLASH.
+*/
+
+void flash_lock(void)
+{
+ FLASH_CR |= FLASH_CR_LOCK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Programming Error Status Flag
+
+*/
+
+void flash_clear_pgerr_flag(void)
+{
+ FLASH_SR |= FLASH_SR_PGERR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the End of Operation Status Flag
+
+*/
+
+void flash_clear_eop_flag(void)
+{
+ FLASH_SR |= FLASH_SR_EOP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Write Protect Error Status Flag
+
+*/
+
+void flash_clear_wrprterr_flag(void)
+{
+ FLASH_SR |= FLASH_SR_WRPRTERR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Busy Status Flag
+
+*/
+
+void flash_clear_bsy_flag(void)
+{
+ FLASH_SR &= ~FLASH_SR_BSY;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Wait until Last Operation has Ended
+
+This loops indefinitely until an operation (write or erase) has completed by
+testing the busy flag.
+*/
+
+void flash_wait_for_last_operation(void)
+{
+ while ((flash_get_status_flags() & FLASH_SR_BSY) == FLASH_SR_BSY);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program a 32 bit Word to FLASH
+
+This performs all operations necessary to program a 32 bit word to FLASH memory.
+The program error flag should be checked separately for the event that memory
+was not properly erased.
+
+Status bit polling is used to detect end of operation.
+
+@param[in] uint32_t address. Full address of flash word to be programmed.
+@param[in] uint32_t data.
+*/
+
+void flash_program_word(uint32_t address, uint32_t data)
+{
+ flash_program_half_word(address,(uint16_t)data);
+ flash_program_half_word(address+2,(uint16_t)(data>>16));
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Unlock the Option Byte Access
+
+This enables write access to the option bytes. It is locked by default on
+reset.
+*/
+
+void flash_unlock_option_bytes(void)
+{
+ /* F1 uses same keys for flash and option */
+ FLASH_OPTKEYR = FLASH_KEYR_KEY1;
+ FLASH_OPTKEYR = FLASH_KEYR_KEY2;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Erase All Option Bytes
+
+This performs all operations necessary to erase the option bytes. These must
+first be fully erased before attempting to program them, therefore it is
+recommended to check these after an erase attempt.
+*/
+
+void flash_erase_option_bytes(void)
+{
+ flash_wait_for_last_operation();
+
+ if ((FLASH_CR & FLASH_CR_OPTWRE) == 0) {
+ flash_unlock_option_bytes();
+ }
+
+ FLASH_CR |= FLASH_CR_OPTER; /* Enable option byte erase. */
+ FLASH_CR |= FLASH_CR_STRT;
+ flash_wait_for_last_operation();
+ FLASH_CR &= ~FLASH_CR_OPTER; /* Disable option byte erase. */
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program the Option Bytes
+
+This performs all operations necessary to program the option bytes.
+The write protect error flag should be checked separately for the event that
+an option byte had not been properly erased before calling this function.
+
+Only the lower 8 bits of the data is significant.
+
+@param[in] uint32_t address. Address of option byte from @ref flash_options.
+@param[in] uint16_t data.
+*/
+
+void flash_program_option_bytes(uint32_t address, uint16_t data)
+{
+ flash_wait_for_last_operation();
+
+ if ((FLASH_CR & FLASH_CR_OPTWRE) == 0) {
+ flash_unlock_option_bytes();
+ }
+
+ FLASH_CR |= FLASH_CR_OPTPG; /* Enable option byte programming. */
+ MMIO16(address) = data;
+ flash_wait_for_last_operation();
+ FLASH_CR &= ~FLASH_CR_OPTPG; /* Disable option byte programming. */
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/flash_common_f234.c b/libopencm3/lib/stm32/common/flash_common_f234.c
new file mode 100644
index 0000000..1d99566
--- /dev/null
+++ b/libopencm3/lib/stm32/common/flash_common_f234.c
@@ -0,0 +1,121 @@
+/** @addtogroup flash_file
+ *
+ */
+
+/*
+ * 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>
+ *
+ * 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 Set the Number of Wait States
+
+Used to match the system clock to the FLASH memory access time. See the
+programming manual for more information on clock speed ranges. The latency must
+be changed to the appropriate value <b>before</b> any increase in clock
+speed, or <b>after</b> any decrease in clock speed.
+
+@param[in] uint32_t ws: values from @ref flash_latency.
+*/
+
+void flash_set_ws(uint32_t ws)
+{
+ uint32_t reg32;
+
+ reg32 = FLASH_ACR;
+ reg32 &= ~((1 << 0) | (1 << 1) | (1 << 2));
+ reg32 |= ws;
+ FLASH_ACR = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Unlock the Flash Program and Erase Controller
+
+This enables write access to the Flash memory. It is locked by default on
+reset.
+*/
+
+void flash_unlock(void)
+{
+ /* Clear the unlock sequence state. */
+ FLASH_CR |= FLASH_CR_LOCK;
+
+ /* Authorize the FPEC access. */
+ FLASH_KEYR = FLASH_KEYR_KEY1;
+ FLASH_KEYR = FLASH_KEYR_KEY2;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Lock the Flash Program and Erase Controller
+
+Used to prevent spurious writes to FLASH.
+*/
+
+void flash_lock(void)
+{
+ FLASH_CR |= FLASH_CR_LOCK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Programming Error Status Flag
+
+*/
+
+void flash_clear_pgperr_flag(void)
+{
+ FLASH_SR |= FLASH_SR_PGPERR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the End of Operation Status Flag
+
+*/
+
+void flash_clear_eop_flag(void)
+{
+ FLASH_SR |= FLASH_SR_EOP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Busy Status Flag
+
+*/
+
+void flash_clear_bsy_flag(void)
+{
+ FLASH_SR &= ~FLASH_SR_BSY;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief Wait until Last Operation has Ended
+
+This loops indefinitely until an operation (write or erase) has completed by
+testing the busy flag.
+*/
+
+void flash_wait_for_last_operation(void)
+{
+ while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY);
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/flash_common_f24.c b/libopencm3/lib/stm32/common/flash_common_f24.c
new file mode 100644
index 0000000..03883fb
--- /dev/null
+++ b/libopencm3/lib/stm32/common/flash_common_f24.c
@@ -0,0 +1,416 @@
+/** @addtogroup flash_file
+ *
+ */
+
+/*
+ * 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>
+ *
+ * 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 Set the Program Parallelism Size
+
+Set the programming word width. Note carefully the power supply voltage
+restrictions under which the different word sizes may be used. See the
+programming manual for more information.
+
+@param psize: 0 (8-bit), 1 (16-bit), 2 (32-bit), 3 (64-bit)
+*/
+
+static inline void flash_set_program_size(uint32_t psize)
+{
+ FLASH_CR &= ~(((1 << 0) | (1 << 1)) << 8);
+ FLASH_CR |= psize;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the Data Cache
+
+*/
+
+void flash_dcache_enable(void)
+{
+ FLASH_ACR |= FLASH_ACR_DCE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable the Data Cache
+
+*/
+
+void flash_dcache_disable(void)
+{
+ FLASH_ACR &= ~FLASH_ACR_DCE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the Instruction Cache
+
+*/
+
+void flash_icache_enable(void)
+{
+ FLASH_ACR |= FLASH_ACR_ICE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable the Instruction Cache
+
+*/
+
+void flash_icache_disable(void)
+{
+ FLASH_ACR &= ~FLASH_ACR_ICE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the FLASH Prefetch Buffer
+
+This buffer is used for instruction fetches and is enabled by default after
+reset.
+
+Note carefully the clock restrictions under which the prefetch buffer may be
+enabled or disabled. Changes are normally made while the clock is running in
+the power-on low frequency mode before being set to a higher speed mode.
+See the reference manual for details.
+*/
+
+void flash_prefetch_enable(void)
+{
+ FLASH_ACR |= FLASH_ACR_PRFTEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable the FLASH Prefetch Buffer
+
+Note carefully the clock restrictions under which the prefetch buffer may be
+set to disabled. See the reference manual for details.
+*/
+
+void flash_prefetch_disable(void)
+{
+ FLASH_ACR &= ~FLASH_ACR_PRFTEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Reset the Data Cache
+
+The data cache must be disabled for this to have effect.
+*/
+
+void flash_dcache_reset(void)
+{
+ FLASH_ACR |= FLASH_ACR_DCRST;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Reset the Instruction Cache
+
+The instruction cache must be disabled for this to have effect.
+*/
+
+void flash_icache_reset(void)
+{
+ FLASH_ACR |= FLASH_ACR_ICRST;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Programming Sequence Error Flag
+
+This flag is set when incorrect programming configuration has been made.
+*/
+
+void flash_clear_pgserr_flag(void)
+{
+ FLASH_SR |= FLASH_SR_PGSERR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Programming Alignment Error Flag
+
+*/
+
+void flash_clear_pgaerr_flag(void)
+{
+ FLASH_SR |= FLASH_SR_PGAERR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Write Protect Error Flag
+
+*/
+
+void flash_clear_wrperr_flag(void)
+{
+ FLASH_SR |= FLASH_SR_WRPERR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear All Status Flags
+
+Program error, end of operation, write protect error, busy.
+*/
+
+void flash_clear_status_flags(void)
+{
+ flash_clear_pgserr_flag();
+ flash_clear_pgaerr_flag();
+ flash_clear_wrperr_flag();
+ flash_clear_pgperr_flag();
+ flash_clear_eop_flag();
+ flash_clear_bsy_flag();
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Unlock the Option Byte Access
+
+This enables write access to the option bytes. It is locked by default on
+reset.
+*/
+
+void flash_unlock_option_bytes(void)
+{
+ /* Clear the unlock state. */
+ FLASH_OPTCR |= FLASH_OPTCR_OPTLOCK;
+
+ /* Unlock option bytes. */
+ FLASH_OPTKEYR = FLASH_OPTKEYR_KEY1;
+ FLASH_OPTKEYR = FLASH_OPTKEYR_KEY2;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Lock the Option Byte Access
+
+This disables write access to the option bytes. It is locked by default on
+reset.
+*/
+
+void flash_lock_option_bytes(void)
+{
+ FLASH_OPTCR |= FLASH_OPTCR_OPTLOCK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program a 64 bit Word to FLASH
+
+This performs all operations necessary to program a 64 bit word to FLASH memory.
+The program error flag should be checked separately for the event that memory
+was not properly erased.
+
+@param[in] uint32_t address
+@param[in] uint64_t data.
+*/
+
+void flash_program_double_word(uint32_t address, uint64_t data)
+{
+ /* Ensure that all flash operations are complete. */
+ flash_wait_for_last_operation();
+ flash_set_program_size(FLASH_CR_PROGRAM_X64);
+
+ /* Enable writes to flash. */
+ FLASH_CR |= FLASH_CR_PG;
+
+ /* Program the double_word. */
+ MMIO64(address) = data;
+
+ /* Wait for the write to complete. */
+ flash_wait_for_last_operation();
+
+ /* Disable writes to flash. */
+ FLASH_CR &= ~FLASH_CR_PG;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program a 32 bit Word to FLASH
+
+This performs all operations necessary to program a 32 bit word to FLASH memory.
+The program error flag should be checked separately for the event that memory
+was not properly erased.
+
+@param[in] uint32_t address
+@param[in] uint32_t data.
+*/
+
+void flash_program_word(uint32_t address, uint32_t data)
+{
+ /* Ensure that all flash operations are complete. */
+ flash_wait_for_last_operation();
+ flash_set_program_size(FLASH_CR_PROGRAM_X32);
+
+ /* Enable writes to flash. */
+ FLASH_CR |= FLASH_CR_PG;
+
+ /* Program the word. */
+ MMIO32(address) = data;
+
+ /* Wait for the write to complete. */
+ flash_wait_for_last_operation();
+
+ /* Disable writes to flash. */
+ FLASH_CR &= ~FLASH_CR_PG;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program a Half Word to FLASH
+
+This performs all operations necessary to program a 16 bit word to FLASH memory.
+The program error flag should be checked separately for the event that memory
+was not properly erased.
+
+@param[in] uint32_t address
+@param[in] uint16_t data.
+*/
+
+void flash_program_half_word(uint32_t address, uint16_t data)
+{
+ flash_wait_for_last_operation();
+ flash_set_program_size(FLASH_CR_PROGRAM_X16);
+
+ FLASH_CR |= FLASH_CR_PG;
+
+ MMIO16(address) = data;
+
+ flash_wait_for_last_operation();
+
+ FLASH_CR &= ~FLASH_CR_PG; /* Disable the PG bit. */
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program an 8 bit Byte to FLASH
+
+This performs all operations necessary to program an 8 bit byte to FLASH memory.
+The program error flag should be checked separately for the event that memory
+was not properly erased.
+
+@param[in] uint32_t address
+@param[in] uint8_t data.
+*/
+
+void flash_program_byte(uint32_t address, uint8_t data)
+{
+ flash_wait_for_last_operation();
+ flash_set_program_size(FLASH_CR_PROGRAM_X8);
+
+ FLASH_CR |= FLASH_CR_PG;
+
+ MMIO8(address) = data;
+
+ flash_wait_for_last_operation();
+
+ FLASH_CR &= ~FLASH_CR_PG; /* Disable the PG bit. */
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program a Data Block to FLASH
+
+This programs an arbitrary length data block to FLASH memory.
+The program error flag should be checked separately for the event that memory
+was not properly erased.
+
+@param[in] uint32_t address. Starting address in Flash.
+@param[in] uint8_t *data. Pointer to start of data block.
+@param[in] uint32_t len. Length of data block.
+*/
+
+void flash_program(uint32_t address, uint8_t *data, uint32_t len)
+{
+ /* TODO: Use dword and word size program operations where possible for
+ * turbo speed.
+ */
+ uint32_t i;
+ for (i = 0; i < len; i++) {
+ flash_program_byte(address+i, data[i]);
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Erase a Sector of FLASH
+
+This performs all operations necessary to erase a sector in FLASH memory.
+The page should be checked to ensure that it was properly erased. A sector must
+first be fully erased before attempting to program it.
+
+See the reference manual or the FLASH programming manual for details.
+
+@param[in] uint32_t sector (0 - 11).
+@param program_size: 0 (8-bit), 1 (16-bit), 2 (32-bit), 3 (64-bit)
+*/
+
+void flash_erase_sector(uint8_t sector, uint32_t program_size)
+{
+ flash_wait_for_last_operation();
+ flash_set_program_size(program_size);
+
+ FLASH_CR &= ~(0xF << 3);
+ FLASH_CR |= (sector << 3) & 0x78;
+ FLASH_CR |= FLASH_CR_SER;
+ FLASH_CR |= FLASH_CR_STRT;
+
+ flash_wait_for_last_operation();
+ FLASH_CR &= ~FLASH_CR_SER;
+ FLASH_CR &= ~(0xF << 3);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Erase All FLASH
+
+This performs all operations necessary to erase all sectors in the FLASH
+memory.
+
+@param program_size: 0 (8-bit), 1 (16-bit), 2 (32-bit), 3 (64-bit)
+*/
+
+void flash_erase_all_sectors(uint32_t program_size)
+{
+ flash_wait_for_last_operation();
+ flash_set_program_size(program_size);
+
+ FLASH_CR |= FLASH_CR_MER; /* Enable mass erase. */
+ FLASH_CR |= FLASH_CR_STRT; /* Trigger the erase. */
+
+ flash_wait_for_last_operation();
+ FLASH_CR &= ~FLASH_CR_MER; /* Disable mass erase. */
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Program the Option Bytes
+
+This performs all operations necessary to program the option bytes.
+The option bytes do not need to be erased first.
+
+@param[in] uint32_t data to be programmed.
+*/
+
+void flash_program_option_bytes(uint32_t data)
+{
+ flash_wait_for_last_operation();
+
+ if (FLASH_OPTCR & FLASH_OPTCR_OPTLOCK) {
+ flash_unlock_option_bytes();
+ }
+
+ FLASH_OPTCR = data & ~0x3;
+ FLASH_OPTCR |= FLASH_OPTCR_OPTSTRT; /* Enable option byte prog. */
+ flash_wait_for_last_operation();
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/gpio_common_all.c b/libopencm3/lib/stm32/common/gpio_common_all.c
new file mode 100644
index 0000000..3821928
--- /dev/null
+++ b/libopencm3/lib/stm32/common/gpio_common_all.c
@@ -0,0 +1,151 @@
+/** @addtogroup gpio_file
+
+@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
+
+*/
+
+/*
+ * 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/>.
+ */
+
+#define WEAK __attribute__((weak))
+
+#include <libopencm3/stm32/gpio.h>
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set a Group of Pins Atomic
+
+Set one or more pins of the given GPIO port to 1 in an atomic operation.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be changed, use logical OR '|' to separate
+ them.
+*/
+void gpio_set(uint32_t gpioport, uint16_t gpios)
+{
+ GPIO_BSRR(gpioport) = gpios;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear a Group of Pins Atomic
+
+Clear one or more pins of the given GPIO port to 0 in an atomic operation.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be changed, use logical OR '|' to separate
+ them.
+*/
+void gpio_clear(uint32_t gpioport, uint16_t gpios)
+{
+ GPIO_BSRR(gpioport) = (gpios << 16);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Read a Group of Pins.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be read, use logical OR '|' to separate
+ them.
+@return Unsigned int16 value of the pin values. The bit position of the pin
+ value returned corresponds to the pin number.
+*/
+uint16_t gpio_get(uint32_t gpioport, uint16_t gpios)
+{
+ return gpio_port_read(gpioport) & gpios;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Toggle a Group of Pins
+
+Toggle one or more pins of the given GPIO port. This is not an atomic operation.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be changed, use logical OR '|' to separate
+ them.
+*/
+void gpio_toggle(uint32_t gpioport, uint16_t gpios)
+{
+ GPIO_ODR(gpioport) ^= gpios;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Read from a Port
+
+Read the current value of the given GPIO port. Only the lower 16 bits contain
+valid pin data.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@return Unsigned int16. The value held in the specified GPIO port.
+*/
+uint16_t gpio_port_read(uint32_t gpioport)
+{
+ return (uint16_t)GPIO_IDR(gpioport);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Write to a Port
+
+Write a value to the given GPIO port.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] data Unsigned int16. The value to be written to the GPIO port.
+*/
+void gpio_port_write(uint32_t gpioport, uint16_t data)
+{
+ GPIO_ODR(gpioport) = data;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Lock the Configuration of a Group of Pins
+
+The configuration of one or more pins of the given GPIO port is locked. There
+is no mechanism to unlock these via software. Unlocking occurs at the next
+reset.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be locked, use logical OR '|' to separate
+ them.
+*/
+void gpio_port_config_lock(uint32_t gpioport, uint16_t gpios)
+{
+ uint32_t reg32;
+
+ /* Special "Lock Key Writing Sequence", see datasheet. */
+ GPIO_LCKR(gpioport) = GPIO_LCKK | gpios; /* Set LCKK. */
+ GPIO_LCKR(gpioport) = ~GPIO_LCKK & gpios; /* Clear LCKK. */
+ GPIO_LCKR(gpioport) = GPIO_LCKK | gpios; /* Set LCKK. */
+ reg32 = GPIO_LCKR(gpioport); /* Read LCKK. */
+ reg32 = GPIO_LCKR(gpioport); /* Read LCKK again. */
+
+ /* Tell the compiler the variable is actually used. It will get
+ * optimized out anyways.
+ */
+ reg32 = reg32;
+
+ /* If (reg32 & GPIO_LCKK) is true, the lock is now active. */
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/gpio_common_f0234.c b/libopencm3/lib/stm32/common/gpio_common_f0234.c
new file mode 100644
index 0000000..9d79074
--- /dev/null
+++ b/libopencm3/lib/stm32/common/gpio_common_f0234.c
@@ -0,0 +1,206 @@
+/** @addtogroup gpio_file
+
+@author @htmlonly &copy; @endhtmlonly 2009
+Uwe Hermann <uwe@hermann-uwe.de>
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+Each I/O port has 16 individually configurable bits. Many I/O pins share GPIO
+functionality with a number of alternate functions and must be configured to
+the alternate function mode if these are to be accessed. A feature is available
+to remap alternative functions to a limited set of alternative pins in the
+event of a clash of requirements.
+
+The data registers associated with each port for input and output are 32 bit
+with the upper 16 bits unused. The output buffer must be written as a 32 bit
+word, but individual bits may be set or reset separately in atomic operations
+to avoid race conditions during interrupts. Bits may also be individually
+locked to prevent accidental configuration changes. Once locked the
+configuration cannot be changed until after the next reset.
+
+Each port bit can be configured as analog or digital input, the latter can be
+floating or pulled up or down. As outputs they can be configured as either
+push-pull or open drain, digital I/O or alternate function, and with maximum
+output speeds of 2MHz, 10MHz, or 50MHz.
+
+On reset all ports are configured as digital floating input.
+
+@section gpio_api_ex Basic GPIO Handling API.
+
+Example 1: Push-pull digital output actions with pullup on ports C2 and C9
+
+@code
+ gpio_mode_setup(GPIOC, GPIO_MODE_OUTPUT,
+ GPIO_PUPD_PULLUP, GPIO2 | GPIO9);
+ gpio_output_options(GPIOC, GPIO_OTYPE_PP,
+ GPIO_OSPEED_25MHZ, GPIO2 | GPIO9);
+ gpio_set(GPIOC, GPIO2 | GPIO9);
+ gpio_clear(GPIOC, GPIO2);
+ gpio_toggle(GPIOC, GPIO2 | GPIO9);
+ gpio_port_write(GPIOC, 0x204);
+@endcode
+
+Example 2: Digital input on port C12 with pullup
+
+@code
+ gpio_mode_setup(GPIOC, GPIO_MODE_INPUT,
+ GPIO_PUPD_PULLUP, GPIO12);
+ reg16 = gpio_port_read(GPIOC);
+@endcode
+
+*/
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2011 Fergus Noble <fergusnoble@gmail.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/gpio.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set GPIO Pin Mode
+
+Sets the Pin Direction and Analog/Digital Mode, and Output Pin Pullup,
+for a set of GPIO pins on a given GPIO port.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] mode Unsigned int8. Pin mode @ref gpio_mode
+@param[in] pull_up_down Unsigned int8. Pin pullup/pulldown configuration @ref
+gpio_pup
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be set, use bitwise OR '|' to separate
+ them.
+*/
+void gpio_mode_setup(uint32_t gpioport, uint8_t mode, uint8_t pull_up_down,
+ uint16_t gpios)
+{
+ uint16_t i;
+ uint32_t moder, pupd;
+
+ /*
+ * We want to set the config only for the pins mentioned in gpios,
+ * but keeping the others, so read out the actual config first.
+ */
+ moder = GPIO_MODER(gpioport);
+ pupd = GPIO_PUPDR(gpioport);
+
+ for (i = 0; i < 16; i++) {
+ if (!((1 << i) & gpios)) {
+ continue;
+ }
+
+ moder &= ~GPIO_MODE_MASK(i);
+ moder |= GPIO_MODE(i, mode);
+ pupd &= ~GPIO_PUPD_MASK(i);
+ pupd |= GPIO_PUPD(i, pull_up_down);
+ }
+
+ /* Set mode and pull up/down control registers. */
+ GPIO_MODER(gpioport) = moder;
+ GPIO_PUPDR(gpioport) = pupd;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set GPIO Output Options
+
+When the pin is set to output mode, this sets the configuration (analog/digital
+and open drain/push pull) and speed, for a set of GPIO pins on a given GPIO
+port.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] otype Unsigned int8. Pin output type @ref gpio_output_type
+@param[in] speed Unsigned int8. Pin speed @ref gpio_speed
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be set, use bitwise OR '|' to separate
+ them.
+*/
+void gpio_set_output_options(uint32_t gpioport, uint8_t otype, uint8_t speed,
+ uint16_t gpios)
+{
+ uint16_t i;
+ uint32_t ospeedr;
+
+ if (otype == 0x1) {
+ GPIO_OTYPER(gpioport) |= gpios;
+ } else {
+ GPIO_OTYPER(gpioport) &= ~gpios;
+ }
+
+ ospeedr = GPIO_OSPEEDR(gpioport);
+
+ for (i = 0; i < 16; i++) {
+ if (!((1 << i) & gpios)) {
+ continue;
+ }
+ ospeedr &= ~GPIO_OSPEED_MASK(i);
+ ospeedr |= GPIO_OSPEED(i, speed);
+ }
+
+ GPIO_OSPEEDR(gpioport) = ospeedr;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set GPIO Alternate Function Selection
+
+Set the alternate function mapping number for each pin. Most pins have
+alternate functions associated with them. When set to AF mode, a pin may be
+used for one of its allocated alternate functions selected by the number given
+here. To determine the number to be used for the desired function refer to the
+individual datasheet for the particular device. A table is given under the Pin
+Selection chapter.
+
+Note that a number of pins may be set but only with a single AF number. In
+practice this would rarely be useful as each pin is likely to require a
+different number.
+
+@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
+@param[in] alt_func_num Unsigned int8. Pin alternate function number @ref
+gpio_af_num
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be set, use bitwise OR '|' to separate
+ them.
+*/
+void gpio_set_af(uint32_t gpioport, uint8_t alt_func_num, uint16_t gpios)
+{
+ uint16_t i;
+ uint32_t afrl, afrh;
+
+ afrl = GPIO_AFRL(gpioport);
+ afrh = GPIO_AFRH(gpioport);
+
+ for (i = 0; i < 8; i++) {
+ if (!((1 << i) & gpios)) {
+ continue;
+ }
+ afrl &= ~GPIO_AFR_MASK(i);
+ afrl |= GPIO_AFR(i, alt_func_num);
+ }
+
+ for (i = 8; i < 16; i++) {
+ if (!((1 << i) & gpios)) {
+ continue;
+ }
+ afrh &= ~GPIO_AFR_MASK(i - 8);
+ afrh |= GPIO_AFR(i - 8, alt_func_num);
+ }
+
+ GPIO_AFRL(gpioport) = afrl;
+ GPIO_AFRH(gpioport) = afrh;
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/hash_common_f24.c b/libopencm3/lib/stm32/common/hash_common_f24.c
new file mode 100644
index 0000000..24d489c
--- /dev/null
+++ b/libopencm3/lib/stm32/common/hash_common_f24.c
@@ -0,0 +1,163 @@
+/** @addtogroup hash_file
+ *
+ * @author @htmlonly &copy; @endhtmlonly 2013
+ * Mikhail Avkhimenia <mikhail@avkhimenia.net>
+ *
+ * This library supports the HASH processor in the STM32F2 and STM32F4
+ * series of ARM Cortex Microcontrollers by ST Microelectronics.
+ *
+ * LGPL License Terms @ref lgpl_license
+ * */
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Mikhail Avkhimenia <mikhail@avkhimenia.net>
+ *
+ * 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/hash.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Set Mode
+
+Sets up the specified mode - either HASH or HMAC.
+
+@param[in] mode unsigned int8. Hash processor mode: @ref hash_mode
+*/
+
+void hash_set_mode(uint8_t mode)
+{
+ HASH_CR &= ~HASH_CR_MODE;
+ HASH_CR |= mode;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Set Algorithm
+
+Sets up the specified algorithm - either MD5 or SHA1.
+
+@param[in] algorithm unsigned int8. Hash algorithm: @ref hash_algorithm
+*/
+
+void hash_set_algorithm(uint8_t algorithm)
+{
+ HASH_CR &= ~HASH_CR_ALGO;
+ HASH_CR |= algorithm;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Set Data Type
+
+Sets up the specified data type: 32Bit, 16Bit, 8Bit, Bitstring.
+
+@param[in] datatype unsigned int8. Hash data type: @ref hash_data_type
+*/
+
+void hash_set_data_type(uint8_t datatype)
+{
+ HASH_CR &= ~HASH_CR_DATATYPE;
+ HASH_CR |= datatype;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Set Key Length
+
+Sets up the specified key length: Long, Short.
+
+@param[in] keylength unsigned int8. Hash data type: @ref hash_key_length
+*/
+
+void hash_set_key_length(uint8_t keylength)
+{
+ HASH_CR &= ~HASH_CR_LKEY;
+ HASH_CR |= keylength;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Set Last Word Valid Bits
+
+Specifies the number of valid bits in the last word.
+
+@param[in] validbits unsigned int8. Number of valid bits.
+*/
+
+void hash_set_last_word_valid_bits(uint8_t validbits)
+{
+ HASH_STR &= ~(HASH_STR_NBW);
+ HASH_STR |= validbits;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Init
+
+Initializes the HASH processor.
+
+*/
+
+void hash_init()
+{
+ HASH_CR |= HASH_CR_INIT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Add data
+
+Puts data into the HASH processor's queue.
+
+@param[in] data unsigned int32. Hash input data.
+*/
+
+void hash_add_data(uint32_t data)
+{
+ HASH_DIN = data;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Digest
+
+Starts the processing of the last data block.
+
+*/
+
+void hash_digest()
+{
+ HASH_STR |= HASH_STR_DCAL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief HASH Get Hash Result
+
+Makes a copy of the resulting hash.
+
+@param[out] data unsigned int32. Hash 4\5 words long depending on the algorithm.
+@param[in] algorithm unsigned int8. Hash algorithm: @ref hash_algorithm
+*/
+
+void hash_get_result(uint32_t *data)
+{
+ data[0] = HASH_HR[0];
+ data[1] = HASH_HR[1];
+ data[2] = HASH_HR[2];
+ data[3] = HASH_HR[3];
+
+ if ((HASH_CR & HASH_CR_ALGO) == HASH_ALGO_SHA1) {
+ data[4] = HASH_HR[4];
+ }
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/i2c_common_all.c b/libopencm3/lib/stm32/common/i2c_common_all.c
new file mode 100644
index 0000000..886f594
--- /dev/null
+++ b/libopencm3/lib/stm32/common/i2c_common_all.c
@@ -0,0 +1,419 @@
+/** @addtogroup i2c_file
+
+@author @htmlonly &copy; @endhtmlonly 2010
+Thomas Otto <tommi@viadmin.org>
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+Devices can have up to three I2C peripherals. The peripherals support SMBus and
+PMBus variants.
+
+A peripheral begins after reset in Slave mode. To become a Master a start
+condition must be generated. The peripheral will remain in Master mode unless
+a multimaster contention is lost or a stop condition is generated.
+
+@todo all sorts of lovely stuff like DMA, Interrupts, SMBus variant, Status
+register access, Error conditions
+
+*/
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.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/i2c.h>
+#include <libopencm3/stm32/rcc.h>
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Reset.
+
+The I2C peripheral and all its associated configuration registers are placed in
+the reset condition. The reset is effected via the RCC peripheral reset system.
+
+@param[in] i2c Unsigned int32. I2C peripheral identifier @ref i2c_reg_base.
+*/
+
+void i2c_reset(uint32_t i2c)
+{
+ switch (i2c) {
+ case I2C1:
+ rcc_periph_reset_pulse(RST_I2C1);
+ break;
+#if defined(I2C2_BASE)
+ case I2C2:
+ rcc_periph_reset_pulse(RST_I2C2);
+ break;
+#endif
+#if defined(I2C3_BASE)
+ case I2C3:
+ rcc_periph_reset_pulse(RST_I2C3);
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Peripheral Enable.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+
+void i2c_peripheral_enable(uint32_t i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_PE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Peripheral Disable.
+
+This must not be reset while in Master mode until a communication has finished.
+In Slave mode, the peripheral is disabled only after communication has ended.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+
+void i2c_peripheral_disable(uint32_t i2c)
+{
+ I2C_CR1(i2c) &= ~I2C_CR1_PE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Send Start Condition.
+
+If in Master mode this will cause a restart condition to occur at the end of the
+current transmission. If in Slave mode, this will initiate a start condition
+when the current bus activity is completed.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+
+void i2c_send_start(uint32_t i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_START;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Send Stop Condition.
+
+After the current byte transfer this will initiate a stop condition if in Master
+mode, or simply release the bus if in Slave mode.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+
+void i2c_send_stop(uint32_t i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_STOP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Clear Stop Flag.
+
+Clear the "Send Stop" flag in the I2C config register
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_clear_stop(uint32_t i2c)
+{
+ I2C_CR1(i2c) &= ~I2C_CR1_STOP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set the 7 bit Slave Address for the Peripheral.
+
+This sets an address for Slave mode operation, in 7 bit form.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] slave Unsigned int8. Slave address 0...127.
+*/
+
+void i2c_set_own_7bit_slave_address(uint32_t i2c, uint8_t slave)
+{
+ I2C_OAR1(i2c) = (uint16_t)(slave << 1);
+ I2C_OAR1(i2c) &= ~I2C_OAR1_ADDMODE;
+ I2C_OAR1(i2c) |= (1 << 14); /* Datasheet: always keep 1 by software. */
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set the 10 bit Slave Address for the Peripheral.
+
+This sets an address for Slave mode operation, in 10 bit form.
+
+@todo add "I2C_OAR1(i2c) |= (1 << 14);" as above
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] slave Unsigned int16. Slave address 0...1023.
+*/
+
+void i2c_set_own_10bit_slave_address(uint32_t i2c, uint16_t slave)
+{
+ I2C_OAR1(i2c) = (uint16_t)(I2C_OAR1_ADDMODE | slave);
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set Peripheral Clock Frequency.
+
+Set the peripheral clock frequency: 2MHz to 36MHz (the APB frequency). Note
+that this is <b> not </b> the I2C bus clock. This is set in conjunction with
+the Clock Control register to generate the Master bus clock, see @ref
+i2c_set_ccr
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] freq Unsigned int8. Clock Frequency Setting @ref i2c_clock.
+*/
+
+void i2c_set_clock_frequency(uint32_t i2c, uint8_t freq)
+{
+ uint16_t reg16;
+ reg16 = I2C_CR2(i2c) & 0xffc0; /* Clear bits [5:0]. */
+ reg16 |= freq;
+ I2C_CR2(i2c) = reg16;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Send Data.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] data Unsigned int8. Byte to send.
+*/
+
+void i2c_send_data(uint32_t i2c, uint8_t data)
+{
+ I2C_DR(i2c) = data;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set Fast Mode.
+
+Set the clock frequency to the high clock rate mode (up to 400kHz). The actual
+clock frequency must be set with @ref i2c_set_clock_frequency
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+
+void i2c_set_fast_mode(uint32_t i2c)
+{
+ I2C_CCR(i2c) |= I2C_CCR_FS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set Standard Mode.
+
+Set the clock frequency to the standard clock rate mode (up to 100kHz). The
+actual clock frequency must be set with @ref i2c_set_clock_frequency
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+
+void i2c_set_standard_mode(uint32_t i2c)
+{
+ I2C_CCR(i2c) &= ~I2C_CCR_FS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set Bus Clock Frequency.
+
+Set the bus clock frequency. This is a 12 bit number (0...4095) calculated
+from the formulae given in the STM32F1 reference manual in the description
+of the CCR field. It is a divisor of the peripheral clock frequency
+@ref i2c_set_clock_frequency modified by the fast mode setting
+@ref i2c_set_fast_mode
+
+@todo provide additional API assitance to set the clock, eg macros
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] freq Unsigned int16. Bus Clock Frequency Setting 0...4095.
+*/
+
+void i2c_set_ccr(uint32_t i2c, uint16_t freq)
+{
+ uint16_t reg16;
+ reg16 = I2C_CCR(i2c) & 0xf000; /* Clear bits [11:0]. */
+ reg16 |= freq;
+ I2C_CCR(i2c) = reg16;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set the Rise Time.
+
+Set the maximum rise time on the bus according to the I2C specification, as 1
+more than the specified rise time in peripheral clock cycles. This is a 6 bit
+number.
+
+@todo provide additional APIP assistance.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] trise Unsigned int16. Rise Time Setting 0...63.
+*/
+
+void i2c_set_trise(uint32_t i2c, uint16_t trise)
+{
+ I2C_TRISE(i2c) = trise;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Send the 7-bit Slave Address.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] slave Unsigned int16. Slave address 0...1023.
+@param[in] readwrite Unsigned int8. Single bit to instruct slave to receive or
+send @ref i2c_rw.
+*/
+
+void i2c_send_7bit_address(uint32_t i2c, uint8_t slave, uint8_t readwrite)
+{
+ I2C_DR(i2c) = (uint8_t)((slave << 1) | readwrite);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Get Data.
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+uint8_t i2c_get_data(uint32_t i2c)
+{
+ return I2C_DR(i2c) & 0xff;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Enable Interrupt
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] interrupt Unsigned int32. Interrupt to enable.
+*/
+void i2c_enable_interrupt(uint32_t i2c, uint32_t interrupt)
+{
+ I2C_CR2(i2c) |= interrupt;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Disable Interrupt
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] interrupt Unsigned int32. Interrupt to disable.
+*/
+void i2c_disable_interrupt(uint32_t i2c, uint32_t interrupt)
+{
+ I2C_CR2(i2c) &= ~interrupt;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Enable ACK
+
+Enables acking of own 7/10 bit address
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_enable_ack(uint32_t i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_ACK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Disable ACK
+
+Disables acking of own 7/10 bit address
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_disable_ack(uint32_t i2c)
+{
+ I2C_CR1(i2c) &= ~I2C_CR1_ACK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C NACK Next Byte
+
+Causes the I2C controller to NACK the reception of the next byte
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_nack_next(uint32_t i2c)
+{
+ I2C_CR1(i2c) |= I2C_CR1_POS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C NACK Next Byte
+
+Causes the I2C controller to NACK the reception of the current byte
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_nack_current(uint32_t i2c)
+{
+ I2C_CR1(i2c) &= ~I2C_CR1_POS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set clock duty cycle
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+@param[in] dutycycle Unsigned int32. I2C duty cycle @ref i2c_duty_cycle.
+*/
+void i2c_set_dutycycle(uint32_t i2c, uint32_t dutycycle)
+{
+ if (dutycycle == I2C_CCR_DUTY_DIV2) {
+ I2C_CCR(i2c) &= ~I2C_CCR_DUTY;
+ } else {
+ I2C_CCR(i2c) |= I2C_CCR_DUTY;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Enable DMA
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_enable_dma(uint32_t i2c)
+{
+ I2C_CR2(i2c) |= I2C_CR2_DMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Disable DMA
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_disable_dma(uint32_t i2c)
+{
+ I2C_CR2(i2c) &= ~I2C_CR2_DMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Set DMA last transfer
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_set_dma_last_transfer(uint32_t i2c)
+{
+ I2C_CR2(i2c) |= I2C_CR2_LAST;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief I2C Clear DMA last transfer
+
+@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
+*/
+void i2c_clear_dma_last_transfer(uint32_t i2c)
+{
+ I2C_CR2(i2c) &= ~I2C_CR2_LAST;
+}
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/common/iwdg_common_all.c b/libopencm3/lib/stm32/common/iwdg_common_all.c
new file mode 100644
index 0000000..d9aca5a
--- /dev/null
+++ b/libopencm3/lib/stm32/common/iwdg_common_all.c
@@ -0,0 +1,149 @@
+/** @addtogroup iwdg_file
+
+@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies ksarkies@internode.on.net
+
+This library supports the Independent Watchdog Timer System in the STM32F1xx
+series of ARM Cortex Microcontrollers by ST Microelectronics.
+
+The watchdog timer uses the LSI (low speed internal) clock which is low power
+and continues to operate during stop and standby modes. Its frequency is
+nominally 32kHz (40kHz for the STM32F1xx series) but can vary from as low
+as 17kHz up to 60kHz (refer to datasheet electrical characteristics).
+
+Note that the User Configuration option byte provides a means of automatically
+enabling the IWDG timer at power on (with counter value 0xFFF). If the
+relevant bit is not set, the IWDG timer must be enabled by software.
+
+@note: Tested: CPU STM32F103RET6, Board ET-ARM Stamp STM32
+
+*/
+/*
+ * 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/iwdg.h>
+
+#define LSI_FREQUENCY 32000
+#define COUNT_LENGTH 12
+#define COUNT_MASK ((1 << COUNT_LENGTH)-1)
+
+/*---------------------------------------------------------------------------*/
+/** @brief IWDG Enable Watchdog Timer
+
+The watchdog timer is started. The timeout period defaults to 512 milliseconds
+unless it has been previously defined.
+
+*/
+
+void iwdg_start(void)
+{
+ IWDG_KR = IWDG_KR_START;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief IWDG Set Period in Milliseconds
+
+The countdown period is converted into count and prescale values. The maximum
+period is 32.76 seconds; values above this are truncated. Periods less than 1ms
+are not supported by this library.
+
+A delay of up to 5 clock cycles of the LSI clock (about 156 microseconds)
+can occasionally occur if the prescale or preload registers are currently busy
+loading a previous value.
+
+@param[in] period uint32_t Period in milliseconds (< 32760) from a watchdog
+reset until a system reset is issued.
+*/
+
+void iwdg_set_period_ms(uint32_t period)
+{
+ uint32_t count, prescale, reload, exponent;
+
+ /* Set the count to represent ticks of the 32kHz LSI clock */
+ count = (period << 5);
+
+ /* Strip off the first 12 bits to get the prescale value required */
+ prescale = (count >> 12);
+ if (prescale > 256) {
+ exponent = IWDG_PR_DIV256; reload = COUNT_MASK;
+ } else if (prescale > 128) {
+ exponent = IWDG_PR_DIV256; reload = (count >> 8);
+ } else if (prescale > 64) {
+ exponent = IWDG_PR_DIV128; reload = (count >> 7);
+ } else if (prescale > 32) {
+ exponent = IWDG_PR_DIV64; reload = (count >> 6);
+ } else if (prescale > 16) {
+ exponent = IWDG_PR_DIV32; reload = (count >> 5);
+ } else if (prescale > 8) {
+ exponent = IWDG_PR_DIV16; reload = (count >> 4);
+ } else if (prescale > 4) {
+ exponent = IWDG_PR_DIV8; reload = (count >> 3);
+ } else {
+ exponent = IWDG_PR_DIV4; reload = (count >> 2);
+ }
+
+ /* Avoid the undefined situation of a zero count */
+ if (count == 0) {
+ count = 1;
+ }
+
+ while (iwdg_prescaler_busy());
+ IWDG_KR = IWDG_KR_UNLOCK;
+ IWDG_PR = exponent;
+ while (iwdg_reload_busy());
+ IWDG_KR = IWDG_KR_UNLOCK;
+ IWDG_RLR = (reload & COUNT_MASK);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief IWDG Get Reload Register Status
+
+@returns boolean: TRUE if the reload register is busy and unavailable for
+loading a new count value.
+*/
+
+bool iwdg_reload_busy(void)
+{
+ return IWDG_SR & IWDG_SR_RVU;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief IWDG Get Prescaler Register Status
+
+@returns boolean: TRUE if the prescaler register is busy and unavailable for
+loading a new period value.
+*/
+
+bool iwdg_prescaler_busy(void)
+{
+ return IWDG_SR & IWDG_SR_PVU;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief IWDG reset Watchdog Timer
+
+The watchdog timer is reset. The counter restarts from the value in the reload
+register.
+*/
+
+void iwdg_reset(void)
+{
+ IWDG_KR = IWDG_KR_RESET;
+}
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/pwr_common_all.c b/libopencm3/lib/stm32/common/pwr_common_all.c
new file mode 100644
index 0000000..53e6b42
--- /dev/null
+++ b/libopencm3/lib/stm32/common/pwr_common_all.c
@@ -0,0 +1,205 @@
+/** @addtogroup pwr_file PWR
+
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+*/
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Ken Sarkies <ksarkies@internode.on.net>
+ *
+ * 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/pwr.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Backup Domain Write Protection.
+
+This allows backup domain registers to be changed. These registers are write
+protected after a reset.
+*/
+
+void pwr_disable_backup_domain_write_protect(void)
+{
+ PWR_CR |= PWR_CR_DBP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Re-enable Backup Domain Write Protection.
+
+This protects backup domain registers from inadvertent change.
+*/
+
+void pwr_enable_backup_domain_write_protect(void)
+{
+ PWR_CR &= ~PWR_CR_DBP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Power Voltage Detector.
+
+This provides voltage level threshold detection. The result of detection is
+provided in the power voltage detector output flag (see @ref pwr_voltage_high)
+or by setting the EXTI16 interrupt (see datasheet for configuration details).
+
+@param[in] pvd_level uint32_t. Taken from @ref pwr_pls.
+*/
+
+void pwr_enable_power_voltage_detect(uint32_t pvd_level)
+{
+ PWR_CR &= ~PWR_CR_PLS_MASK;
+ PWR_CR |= (PWR_CR_PVDE | pvd_level);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Power Voltage Detector.
+
+*/
+
+void pwr_disable_power_voltage_detect(void)
+{
+ PWR_CR &= ~PWR_CR_PVDE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Standby Flag.
+
+This is set when the processor returns from a standby mode.
+*/
+
+void pwr_clear_standby_flag(void)
+{
+ PWR_CR |= PWR_CR_CSBF;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear the Wakeup Flag.
+
+This is set when the processor receives a wakeup signal.
+*/
+
+void pwr_clear_wakeup_flag(void)
+{
+ PWR_CR |= PWR_CR_CWUF;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Standby Mode in Deep Sleep.
+
+*/
+
+void pwr_set_standby_mode(void)
+{
+ PWR_CR |= PWR_CR_PDDS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Stop Mode in Deep Sleep.
+
+*/
+
+void pwr_set_stop_mode(void)
+{
+ PWR_CR &= ~PWR_CR_PDDS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Voltage Regulator On in Stop Mode.
+
+*/
+
+void pwr_voltage_regulator_on_in_stop(void)
+{
+ PWR_CR &= ~PWR_CR_LPDS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Voltage Regulator Low Power in Stop Mode.
+
+*/
+
+void pwr_voltage_regulator_low_power_in_stop(void)
+{
+ PWR_CR |= PWR_CR_LPDS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Wakeup Pin.
+
+The wakeup pin is used for waking the processor from standby mode.
+*/
+
+void pwr_enable_wakeup_pin(void)
+{
+ PWR_CSR |= PWR_CSR_EWUP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Release Wakeup Pin.
+
+The wakeup pin is used for general purpose I/O.
+*/
+
+void pwr_disable_wakeup_pin(void)
+{
+ PWR_CSR &= ~PWR_CSR_EWUP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Get Voltage Detector Output.
+
+The voltage detector threshold must be set when the power voltage detector is
+enabled, see @ref pwr_enable_power_voltage_detect.
+
+@returns boolean: TRUE if the power voltage is above the preset voltage
+threshold.
+*/
+
+bool pwr_voltage_high(void)
+{
+ return PWR_CSR & PWR_CSR_PVDO;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Get Standby Flag.
+
+The standby flag is set when the processor returns from a standby state. It is
+cleared by software (see @ref pwr_clear_standby_flag).
+
+@returns boolean: TRUE if the processor was in standby state.
+*/
+
+bool pwr_get_standby_flag(void)
+{
+ return PWR_CSR & PWR_CSR_SBF;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Get Wakeup Flag.
+
+The wakeup flag is set when a wakeup event has been received. It is
+cleared by software (see @ref pwr_clear_wakeup_flag).
+
+@returns boolean: TRUE if a wakeup event was received.
+*/
+
+bool pwr_get_wakeup_flag(void)
+{
+ return PWR_CSR & PWR_CSR_WUF;
+}
+/**@}*/
diff --git a/libopencm3/lib/stm32/common/rcc_common_all.c b/libopencm3/lib/stm32/common/rcc_common_all.c
new file mode 100644
index 0000000..41cb814
--- /dev/null
+++ b/libopencm3/lib/stm32/common/rcc_common_all.c
@@ -0,0 +1,188 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2013 Frantisek Burian <bufran@seznam.cz>
+ * .. file is merged from many other copyrighted files of stm32 family
+ *
+ * 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/rcc.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Enable Peripheral Clocks.
+ *
+ * Enable the clock on particular peripherals. There are three registers
+ * involved, each one controlling the enabling of clocks associated with the
+ * AHB, APB1 and APB2 respectively. Several peripherals could be enabled
+ * simultaneously <em>only if they are controlled by the same register</em>.
+ *
+ * @param[in] *reg Unsigned int32. Pointer to a Clock Enable Register
+ * (either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR)
+ *
+ * @param[in] en Unsigned int32. Logical OR of all enables to be set
+ * @li If register is RCC_AHBER, from @ref rcc_ahbenr_en
+ * @li If register is RCC_APB1ENR, from @ref rcc_apb1enr_en
+ * @li If register is RCC_APB2ENR, from @ref rcc_apb2enr_en
+ */
+
+void rcc_peripheral_enable_clock(volatile uint32_t *reg, uint32_t en)
+{
+ *reg |= en;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Disable Peripheral Clocks.
+ *
+ * Enable the clock on particular peripherals. There are three registers
+ * involved, each one controlling the enabling of clocks associated with
+ * the AHB, APB1 and APB2 respectively. Several peripherals could be disabled
+ * simultaneously <em>only if they are controlled by the same register</em>.
+ *
+ * @param[in] *reg Unsigned int32. Pointer to a Clock Enable Register
+ * (either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR)
+ * @param[in] en Unsigned int32. Logical OR of all enables to be used for
+ * disabling.
+ * @li If register is RCC_AHBER, from @ref rcc_ahbenr_en
+ * @li If register is RCC_APB1ENR, from @ref rcc_apb1enr_en
+ * @li If register is RCC_APB2ENR, from @ref rcc_apb2enr_en
+ */
+void rcc_peripheral_disable_clock(volatile uint32_t *reg, uint32_t en)
+{
+ *reg &= ~en;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Reset Peripherals.
+ *
+ * Reset particular peripherals. There are three registers involved, each one
+ * controlling reset of peripherals associated with the AHB, APB1 and APB2
+ * respectively. Several peripherals could be reset simultaneously <em>only if
+ * they are controlled by the same register</em>.
+ *
+ * @param[in] *reg Unsigned int32. Pointer to a Reset Register
+ * (either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR)
+ * @param[in] reset Unsigned int32. Logical OR of all resets.
+ * @li If register is RCC_AHBRSTR, from @ref rcc_ahbrstr_rst
+ * @li If register is RCC_APB1RSTR, from @ref rcc_apb1rstr_rst
+ * @li If register is RCC_APB2RSTR, from @ref rcc_apb2rstr_rst
+ */
+void rcc_peripheral_reset(volatile uint32_t *reg, uint32_t reset)
+{
+ *reg |= reset;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief RCC Remove Reset on Peripherals.
+ *
+ * Remove the reset on particular peripherals. There are three registers
+ * involved, each one controlling reset of peripherals associated with the AHB,
+ * APB1 and APB2 respectively. Several peripherals could have the reset removed
+ * simultaneously <em>only if they are controlled by the same register</em>.
+ *
+ * @param[in] *reg Unsigned int32. Pointer to a Reset Register
+ * (either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR)
+ * @param[in] clear_reset Unsigned int32. Logical OR of all resets to be
+ * removed:
+ * @li If register is RCC_AHBRSTR, from @ref rcc_ahbrstr_rst
+ * @li If register is RCC_APB1RSTR, from @ref rcc_apb1rstr_rst
+ * @li If register is RCC_APB2RSTR, from @ref rcc_apb2rstr_rst
+ */
+void rcc_peripheral_clear_reset(volatile uint32_t *reg, uint32_t clear_reset)
+{
+ *reg &= ~clear_reset;
+}
+
+#define _RCC_REG(i) MMIO32(RCC_BASE + ((i) >> 5))
+#define _RCC_BIT(i) (1 << ((i) & 0x1f))
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Peripheral Clock in running mode.
+ *
+ * Enable the clock on particular peripheral.
+ *
+ * @param[in] clken rcc_periph_clken Peripheral RCC
+ *
+ * For available constants, see #rcc_periph_clken (RCC_UART1 for example)
+ */
+
+void rcc_periph_clock_enable(enum rcc_periph_clken clken)
+{
+ _RCC_REG(clken) |= _RCC_BIT(clken);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Peripheral Clock in running mode.
+ * Disable the clock on particular peripheral.
+ *
+ * @param[in] clken rcc_periph_clken Peripheral RCC
+ *
+ * For available constants, see #rcc_periph_clken (RCC_UART1 for example)
+ */
+
+void rcc_periph_clock_disable(enum rcc_periph_clken clken)
+{
+ _RCC_REG(clken) &= ~_RCC_BIT(clken);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Reset Peripheral, pulsed
+ *
+ * Reset particular peripheral, and restore to working state.
+ *
+ * @param[in] rst rcc_periph_rst Peripheral reset
+ *
+ * For available constants, see #rcc_periph_rst (RST_UART1 for example)
+ */
+
+void rcc_periph_reset_pulse(enum rcc_periph_rst rst)
+{
+ _RCC_REG(rst) |= _RCC_BIT(rst);
+ _RCC_REG(rst) &= ~_RCC_BIT(rst);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Reset Peripheral, hold
+ *
+ * Reset particular peripheral, and hold in reset state.
+ *
+ * @param[in] rst rcc_periph_rst Peripheral reset
+ *
+ * For available constants, see #rcc_periph_rst (RST_UART1 for example)
+ */
+
+void rcc_periph_reset_hold(enum rcc_periph_rst rst)
+{
+ _RCC_REG(rst) |= _RCC_BIT(rst);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Reset Peripheral, release
+ *
+ * Restore peripheral from reset state to working state.
+ *
+ * @param[in] rst rcc_periph_rst Peripheral reset
+ *
+ * For available constants, see #rcc_periph_rst (RST_UART1 for example)
+ */
+
+void rcc_periph_reset_release(enum rcc_periph_rst rst)
+{
+ _RCC_REG(rst) &= ~_RCC_BIT(rst);
+}
+/**@}*/
+
+#undef _RCC_REG
+#undef _RCC_BIT
diff --git a/libopencm3/lib/stm32/common/rtc_common_l1f024.c b/libopencm3/lib/stm32/common/rtc_common_l1f024.c
new file mode 100644
index 0000000..7579dfd
--- /dev/null
+++ b/libopencm3/lib/stm32/common/rtc_common_l1f024.c
@@ -0,0 +1,123 @@
+/** @addtogroup rtc_file
+
+@author @htmlonly &copy; @endhtmlonly 2012 Karl Palsson <karlp@tweak.net.au>
+
+*/
+
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * 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/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/rtc.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set RTC prescalars.
+
+This sets the RTC synchronous and asynchronous prescalars.
+*/
+
+void rtc_set_prescaler(uint32_t sync, uint32_t async)
+{
+ /*
+ * Even if only one of the two fields needs to be changed,
+ * 2 separate write accesses must be performed to the RTC_PRER register.
+ */
+ RTC_PRER = (sync & RTC_PRER_PREDIV_S_MASK);
+ RTC_PRER |= (async << RTC_PRER_PREDIV_A_SHIFT);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Wait for RTC registers to be synchronised with the APB1 bus
+
+ Time and Date are accessed through shadow registers which must be synchronized
+*/
+
+void rtc_wait_for_synchro(void)
+{
+ /* Unlock RTC registers */
+ RTC_WPR = 0xca;
+ RTC_WPR = 0x53;
+
+ RTC_ISR &= ~(RTC_ISR_RSF);
+
+ while (!(RTC_ISR & RTC_ISR_RSF));
+
+ /* disable write protection again */
+ RTC_WPR = 0xff;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Unlock write access to the RTC registers
+
+*/
+void rtc_unlock(void)
+{
+ RTC_WPR = 0xca;
+ RTC_WPR = 0x53;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Lock write access to the RTC registers
+
+*/
+void rtc_lock(void)
+{
+ RTC_WPR = 0xff;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Sets the wakeup time auto-reload value
+
+*/
+void rtc_set_wakeup_time(uint16_t wkup_time, uint8_t rtc_cr_wucksel)
+{
+ /* FTFM:
+ * The following sequence is required to configure or change the wakeup
+ * timer auto-reload value (WUT[15:0] in RTC_WUTR):
+ * 1. Clear WUTE in RTC_CR to disable the wakeup timer.
+ */
+ RTC_CR &= ~RTC_CR_WUTE;
+ /* 2. Poll WUTWF until it is set in RTC_ISR to make sure the access to
+ * wakeup auto-reload counter and to WUCKSEL[2:0] bits is allowed.
+ * It takes around 2 RTCCLK clock cycles (due to clock
+ * synchronization).
+ */
+ while (!((RTC_ISR) & (RTC_ISR_WUTWF)));
+ /* 3. Program the wakeup auto-reload value WUT[15:0], and the wakeup
+ * clock selection (WUCKSEL[2:0] bits in RTC_CR).Set WUTE in RTC_CR
+ * to enable the timer again. The wakeup timer restarts
+ * down-counting.
+ */
+ RTC_WUTR = wkup_time;
+ RTC_CR |= (rtc_cr_wucksel << RTC_CR_WUCLKSEL_SHIFT);
+ RTC_CR |= RTC_CR_WUTE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clears the wakeup flag
+
+@details This function should be called first in the rtc_wkup_isr()
+*/
+void rtc_clear_wakeup_flag(void)
+{
+ RTC_ISR &= ~RTC_ISR_WUTF;
+}
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/common/spi_common_all.c b/libopencm3/lib/stm32/common/spi_common_all.c
new file mode 100644
index 0000000..6572233
--- /dev/null
+++ b/libopencm3/lib/stm32/common/spi_common_all.c
@@ -0,0 +1,710 @@
+/** @addtogroup spi_file
+
+@author @htmlonly &copy; @endhtmlonly 2009
+Uwe Hermann <uwe@hermann-uwe.de>
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+Devices can have up to three SPI peripherals. The common 4-wire full-duplex
+mode of operation is supported, along with 3-wire variants using unidirectional
+communication modes or half-duplex bidirectional communication. A variety of
+options allows many of the SPI variants to be supported. Multimaster operation
+is also supported. A CRC can be generated and checked in hardware.
+
+@note Some JTAG pins need to be remapped if SPI is to be used.
+
+@note The I2S protocol shares the SPI hardware so the two protocols cannot be
+used at the same time on the same peripheral.
+
+Example: 1Mbps, positive clock polarity, leading edge trigger, 8-bit words,
+LSB first.
+@code
+ spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
+ SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT,
+ SPI_CR1_LSBFIRST);
+ spi_write(SPI1, 0x55); // 8-bit write
+ spi_write(SPI1, 0xaa88); // 16-bit write
+ reg8 = spi_read(SPI1); // 8-bit read
+ reg16 = spi_read(SPI1); // 16-bit read
+@endcode
+
+@todo need additional functions to aid ISRs in retrieving status
+
+*/
+
+/*
+ * 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/>.
+ */
+
+#include <libopencm3/stm32/spi.h>
+#include <libopencm3/stm32/rcc.h>
+
+/*
+ * SPI and I2S code.
+ *
+ * Examples:
+ * spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
+ * SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT,
+ * SPI_CR1_LSBFIRST);
+ * spi_write(SPI1, 0x55); // 8-bit write
+ * spi_write(SPI1, 0xaa88); // 16-bit write
+ * reg8 = spi_read(SPI1); // 8-bit read
+ * reg16 = spi_read(SPI1); // 16-bit read
+ */
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Reset.
+
+The SPI peripheral and all its associated configuration registers are placed in
+the reset condition. The reset is effected via the RCC peripheral reset system.
+
+@param[in] spi_peripheral Unsigned int32. SPI peripheral identifier @ref
+spi_reg_base.
+*/
+
+void spi_reset(uint32_t spi_peripheral)
+{ switch (spi_peripheral) {
+#if defined(SPI1_BASE)
+ case SPI1_BASE:
+ rcc_periph_reset_pulse(RST_SPI1);
+ break;
+#endif
+#if defined(SPI2_I2S_BASE)
+ case SPI2_I2S_BASE:
+ rcc_periph_reset_pulse(RST_SPI2);
+ break;
+#endif
+#if defined(SPI3_I2S_BASE)
+ case SPI3_I2S_BASE:
+ rcc_periph_reset_pulse(RST_SPI3);
+ break;
+#endif
+#if defined(SPI4_BASE)
+ case SPI4_BASE:
+ rcc_periph_reset_pulse(RST_SPI4);
+ break;
+#endif
+#if defined(SPI5_BASE)
+ case SPI5_BASE:
+ rcc_periph_reset_pulse(RST_SPI5);
+ break;
+#endif
+#if defined(SPI6_BASE)
+ case SPI6_BASE:
+ rcc_periph_reset_pulse(RST_SPI6);
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+/* TODO: Error handling? */
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable.
+
+The SPI peripheral is enabled.
+
+@todo Error handling?
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_SPE; /* Enable SPI. */
+}
+
+/* TODO: Error handling? */
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Disable.
+
+The SPI peripheral is disabled.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable(uint32_t spi)
+{
+ uint32_t reg32;
+
+ reg32 = SPI_CR1(spi);
+ reg32 &= ~(SPI_CR1_SPE); /* Disable SPI. */
+ SPI_CR1(spi) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Clean Disable.
+
+Disable the SPI peripheral according to the procedure in section 23.3.8 of the
+reference manual. This prevents corruption of any ongoing transfers and
+prevents the BSY flag from becoming unreliable.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+@returns data Unsigned int16. 8 or 16 bit data from final read.
+*/
+
+uint16_t spi_clean_disable(uint32_t spi)
+{
+ /* Wait to receive last data */
+ while (!(SPI_SR(spi) & SPI_SR_RXNE));
+
+ uint16_t data = SPI_DR(spi);
+
+ /* Wait to transmit last data */
+ while (!(SPI_SR(spi) & SPI_SR_TXE));
+
+ /* Wait until not busy */
+ while (SPI_SR(spi) & SPI_SR_BSY);
+
+ SPI_CR1(spi) &= ~SPI_CR1_SPE;
+
+ return data;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Data Write.
+
+Data is written to the SPI interface.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+@param[in] data Unsigned int16. 8 or 16 bit data to be written.
+*/
+
+void spi_write(uint32_t spi, uint16_t data)
+{
+ /* Write data (8 or 16 bits, depending on DFF) into DR. */
+ SPI_DR(spi) = data;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Data Write with Blocking.
+
+Data is written to the SPI interface after the previous write transfer has
+finished.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+@param[in] data Unsigned int16. 8 or 16 bit data to be written.
+*/
+
+void spi_send(uint32_t spi, uint16_t data)
+{
+ /* Wait for transfer finished. */
+ while (!(SPI_SR(spi) & SPI_SR_TXE));
+
+ /* Write data (8 or 16 bits, depending on DFF) into DR. */
+ SPI_DR(spi) = data;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Data Read.
+
+Data is read from the SPI interface after the incoming transfer has finished.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+@returns data Unsigned int16. 8 or 16 bit data.
+*/
+
+uint16_t spi_read(uint32_t spi)
+{
+ /* Wait for transfer finished. */
+ while (!(SPI_SR(spi) & SPI_SR_RXNE));
+
+ /* Read the data (8 or 16 bits, depending on DFF bit) from DR. */
+ return SPI_DR(spi);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Data Write and Read Exchange.
+
+Data is written to the SPI interface, then a read is done after the incoming
+transfer has finished.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+@param[in] data Unsigned int16. 8 or 16 bit data to be written.
+@returns data Unsigned int16. 8 or 16 bit data.
+*/
+
+uint16_t spi_xfer(uint32_t spi, uint16_t data)
+{
+ spi_write(spi, data);
+
+ /* Wait for transfer finished. */
+ while (!(SPI_SR(spi) & SPI_SR_RXNE));
+
+ /* Read the data (8 or 16 bits, depending on DFF bit) from DR. */
+ return SPI_DR(spi);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set Bidirectional Simplex Mode.
+
+The SPI peripheral is set for bidirectional transfers in two-wire simplex mode
+(using a clock wire and a bidirectional data wire).
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_bidirectional_mode(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_BIDIMODE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set Unidirectional Mode.
+
+The SPI peripheral is set for unidirectional transfers. This is used in full
+duplex mode or when the SPI is placed in two-wire simplex mode that uses a
+clock wire and a unidirectional data wire.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_unidirectional_mode(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_BIDIMODE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set Bidirectional Simplex Receive Only Mode.
+
+The SPI peripheral is set for bidirectional transfers in two-wire simplex mode
+(using a clock wire and a bidirectional data wire), and is placed in a receive
+state.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_bidirectional_receive_only_mode(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_BIDIMODE;
+ SPI_CR1(spi) &= ~SPI_CR1_BIDIOE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set Bidirectional Simplex Receive Only Mode.
+
+The SPI peripheral is set for bidirectional transfers in two-wire simplex mode
+(using a clock wire and a bidirectional data wire), and is placed in a transmit
+state.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_bidirectional_transmit_only_mode(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_BIDIMODE;
+ SPI_CR1(spi) |= SPI_CR1_BIDIOE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable the CRC.
+
+The SPI peripheral is set to use a CRC field for transmit and receive.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable_crc(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_CRCEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Disable the CRC.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable_crc(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_CRCEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Next Transmit is a Data Word
+
+The next transmission to take place is a data word from the transmit buffer.
+This must be called before transmission to distinguish between sending
+of a data or CRC word.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_next_tx_from_buffer(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_CRCNEXT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Next Transmit is a CRC Word
+
+The next transmission to take place is a crc word from the hardware crc unit.
+This must be called before transmission to distinguish between sending
+of a data or CRC word.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_next_tx_from_crc(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_CRCNEXT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set Full Duplex (3-wire) Mode
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_full_duplex_mode(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_RXONLY;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set Receive Only Mode for Simplex (2-wire) Unidirectional
+Transfers
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_receive_only_mode(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_RXONLY;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable Slave Management by Hardware
+
+In slave mode the NSS hardware input is used as a select enable for the slave.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable_software_slave_management(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_SSM;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable Slave Management by Software
+
+In slave mode the NSS hardware input is replaced by an internal software
+enable/disable of the slave (@ref spi_set_nss_high).
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable_software_slave_management(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_SSM;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the Software NSS Signal High
+
+In slave mode, and only when software slave management is used, this replaces
+the NSS signal with a slave select enable signal.
+
+@todo these should perhaps be combined with an SSM enable as it is meaningless
+otherwise
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_nss_high(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_SSI;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the Software NSS Signal Low
+
+In slave mode, and only when software slave management is used, this replaces
+the NSS signal with a slave select disable signal.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_nss_low(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_SSI;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set to Send LSB First
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_send_lsb_first(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_LSBFIRST;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set to Send MSB First
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_send_msb_first(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_LSBFIRST;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the Baudrate Prescaler
+
+@todo Why is this specification different to the spi_init_master baudrate
+values?
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+@param[in] baudrate Unsigned int8. Baudrate prescale value @ref spi_br_pre.
+*/
+
+void spi_set_baudrate_prescaler(uint32_t spi, uint8_t baudrate)
+{
+ uint32_t reg32;
+
+ if (baudrate > 7) {
+ return;
+ }
+
+ reg32 = (SPI_CR1(spi) & 0xffc7); /* Clear bits [5:3]. */
+ reg32 |= (baudrate << 3);
+ SPI_CR1(spi) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set to Master Mode
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_master_mode(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_MSTR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set to Slave Mode
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_slave_mode(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_MSTR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the Clock Polarity to High when Idle
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_clock_polarity_1(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_CPOL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the Clock Polarity to Low when Idle
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_clock_polarity_0(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_CPOL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the Clock Phase to Capture on Trailing Edge
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_clock_phase_1(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_CPHA;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the Clock Phase to Capture on Leading Edge
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_clock_phase_0(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_CPHA;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable the Transmit Buffer Empty Interrupt
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable_tx_buffer_empty_interrupt(uint32_t spi)
+{
+ SPI_CR2(spi) |= SPI_CR2_TXEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Disable the Transmit Buffer Empty Interrupt
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable_tx_buffer_empty_interrupt(uint32_t spi)
+{
+ SPI_CR2(spi) &= ~SPI_CR2_TXEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable the Receive Buffer Ready Interrupt
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable_rx_buffer_not_empty_interrupt(uint32_t spi)
+{
+ SPI_CR2(spi) |= SPI_CR2_RXNEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Disable the Receive Buffer Ready Interrupt
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable_rx_buffer_not_empty_interrupt(uint32_t spi)
+{
+ SPI_CR2(spi) &= ~SPI_CR2_RXNEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable the Error Interrupt
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable_error_interrupt(uint32_t spi)
+{
+ SPI_CR2(spi) |= SPI_CR2_ERRIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Disable the Error Interrupt
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable_error_interrupt(uint32_t spi)
+{
+ SPI_CR2(spi) &= ~SPI_CR2_ERRIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the NSS Pin as an Output
+
+Normally used in master mode to allows the master to place all devices on the
+SPI bus into slave mode. Multimaster mode is not possible.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable_ss_output(uint32_t spi)
+{
+ SPI_CR2(spi) |= SPI_CR2_SSOE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set the NSS Pin as an Input
+
+In master mode this allows the master to sense the presence of other masters. If
+NSS is then pulled low the master is placed into slave mode. In slave mode NSS
+becomes a slave enable.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable_ss_output(uint32_t spi)
+{
+ SPI_CR2(spi) &= ~SPI_CR2_SSOE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable Transmit Transfers via DMA
+
+This allows transmissions to proceed unattended using DMA to move data to the
+transmit buffer as it becomes available. The DMA channels provided for each
+SPI peripheral are given in the Technical Manual DMA section.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable_tx_dma(uint32_t spi)
+{
+ SPI_CR2(spi) |= SPI_CR2_TXDMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Disable Transmit Transfers via DMA
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable_tx_dma(uint32_t spi)
+{
+ SPI_CR2(spi) &= ~SPI_CR2_TXDMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Enable Receive Transfers via DMA
+
+This allows received data streams to proceed unattended using DMA to move data
+from the receive buffer as data becomes available. The DMA channels provided
+for each SPI peripheral are given in the Technical Manual DMA section.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_enable_rx_dma(uint32_t spi)
+{
+ SPI_CR2(spi) |= SPI_CR2_RXDMAEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Disable Receive Transfers via DMA
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_disable_rx_dma(uint32_t spi)
+{
+ SPI_CR2(spi) &= ~SPI_CR2_RXDMAEN;
+}
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/common/spi_common_f03.c b/libopencm3/lib/stm32/common/spi_common_f03.c
new file mode 100644
index 0000000..5713653
--- /dev/null
+++ b/libopencm3/lib/stm32/common/spi_common_f03.c
@@ -0,0 +1,177 @@
+/** @addtogroup spi_file
+
+@author @htmlonly &copy; @endhtmlonly 2009
+Uwe Hermann <uwe@hermann-uwe.de>
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+Devices can have up to three SPI peripherals. The common 4-wire full-duplex
+mode of operation is supported, along with 3-wire variants using unidirectional
+communication modes or half-duplex bidirectional communication. A variety of
+options allows many of the SPI variants to be supported. Multimaster operation
+is also supported. A CRC can be generated and checked in hardware.
+
+@note Some JTAG pins need to be remapped if SPI is to be used.
+
+@note The I2S protocol shares the SPI hardware so the two protocols cannot be
+used at the same time on the same peripheral.
+
+Example: 1Mbps, positive clock polarity, leading edge trigger, 8-bit words,
+LSB first.
+@code
+ spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
+ SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_CRCL_8BIT,
+ SPI_CR1_LSBFIRST);
+ spi_write(SPI1, 0x55); // 8-bit write
+ spi_write(SPI1, 0xaa88); // 16-bit write
+ reg8 = spi_read(SPI1); // 8-bit read
+ reg16 = spi_read(SPI1); // 16-bit read
+@endcode
+
+@todo need additional functions to aid ISRs in retrieving status
+
+*/
+
+/*
+ * 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/>.
+ */
+
+#include <libopencm3/stm32/spi.h>
+#include <libopencm3/stm32/rcc.h>
+
+/*
+ * SPI and I2S code.
+ *
+ * Examples:
+ * spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
+ * SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_CRCL_8BIT,
+ * SPI_CR1_LSBFIRST);
+ * spi_write(SPI1, 0x55); // 8-bit write
+ * spi_write(SPI1, 0xaa88); // 16-bit write
+ * reg8 = spi_read(SPI1); // 8-bit read
+ * reg16 = spi_read(SPI1); // 16-bit read
+ */
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief Configure the SPI as Master.
+
+The SPI peripheral is configured as a master with communication parameters
+baudrate, crc length 8/16 bits, frame format lsb/msb first, clock polarity
+and phase. The SPI enable, CRC enable and CRC next controls are not affected.
+These must be controlled separately.
+
+@todo NSS pin handling.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+@param[in] br Unsigned int32. Baudrate @ref spi_baudrate.
+@param[in] cpol Unsigned int32. Clock polarity @ref spi_cpol.
+@param[in] cpha Unsigned int32. Clock Phase @ref spi_cpha.
+@param[in] crcl Unsigned int32. CRC length 8/16 bits @ref spi_crcl.
+@param[in] lsbfirst Unsigned int32. Frame format lsb/msb first @ref
+spi_lsbfirst.
+@returns int. Error code.
+*/
+
+int spi_init_master(uint32_t spi, uint32_t br, uint32_t cpol, uint32_t cpha,
+ uint32_t crcl, uint32_t lsbfirst)
+{
+ uint32_t reg32 = SPI_CR1(spi);
+
+ /* Reset all bits omitting SPE, CRCEN and CRCNEXT bits. */
+ reg32 &= SPI_CR1_SPE | SPI_CR1_CRCEN | SPI_CR1_CRCNEXT;
+
+ reg32 |= SPI_CR1_MSTR; /* Configure SPI as master. */
+
+ reg32 |= br; /* Set baud rate bits. */
+ reg32 |= cpol; /* Set CPOL value. */
+ reg32 |= cpha; /* Set CPHA value. */
+ reg32 |= crcl; /* Set crc length (8 or 16 bits). */
+ reg32 |= lsbfirst; /* Set frame format (LSB- or MSB-first). */
+
+ /* TODO: NSS pin handling. */
+
+ SPI_CR1(spi) = reg32;
+
+ return 0; /* TODO */
+}
+
+void spi_send8(uint32_t spi, uint8_t data)
+{
+ /* Wait for transfer finished. */
+ while (!(SPI_SR(spi) & SPI_SR_TXE));
+
+ /* Write data (8 or 16 bits, depending on DFF) into DR. */
+ SPI_DR8(spi) = data;
+}
+
+uint8_t spi_read8(uint32_t spi)
+{
+ /* Wait for transfer finished. */
+ while (!(SPI_SR(spi) & SPI_SR_RXNE));
+
+ /* Read the data (8 or 16 bits, depending on DFF bit) from DR. */
+ return SPI_DR8(spi);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set CRC length to 8 bits
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_crcl_8bit(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_CRCL;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set CRC length to 16 bits
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_crcl_16bit(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_CRCL;
+}
+
+void spi_set_data_size(uint32_t spi, uint16_t data_s)
+{
+ SPI_CR2(spi) = (SPI_CR2(spi) & ~SPI_CR2_DS_MASK) |
+ (data_s & SPI_CR2_DS_MASK);
+}
+
+void spi_fifo_reception_threshold_8bit(uint32_t spi)
+{
+ SPI_CR2(spi) |= SPI_CR2_FRXTH;
+}
+
+void spi_fifo_reception_threshold_16bit(uint32_t spi)
+{
+ SPI_CR2(spi) &= ~SPI_CR2_FRXTH;
+}
+
+void spi_i2s_mode_spi_mode(uint32_t spi)
+{
+ SPI_I2SCFGR(spi) &= ~SPI_I2SCFGR_I2SMOD;
+}
+
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/common/spi_common_l1f124.c b/libopencm3/lib/stm32/common/spi_common_l1f124.c
new file mode 100644
index 0000000..6345350
--- /dev/null
+++ b/libopencm3/lib/stm32/common/spi_common_l1f124.c
@@ -0,0 +1,137 @@
+/** @addtogroup spi_file
+
+@author @htmlonly &copy; @endhtmlonly 2009
+Uwe Hermann <uwe@hermann-uwe.de>
+@author @htmlonly &copy; @endhtmlonly 2012
+Ken Sarkies <ksarkies@internode.on.net>
+
+Devices can have up to three SPI peripherals. The common 4-wire full-duplex
+mode of operation is supported, along with 3-wire variants using unidirectional
+communication modes or half-duplex bidirectional communication. A variety of
+options allows many of the SPI variants to be supported. Multimaster operation
+is also supported. A CRC can be generated and checked in hardware.
+
+@note Some JTAG pins need to be remapped if SPI is to be used.
+
+@note The I2S protocol shares the SPI hardware so the two protocols cannot be
+used at the same time on the same peripheral.
+
+Example: 1Mbps, positive clock polarity, leading edge trigger, 8-bit words,
+LSB first.
+@code
+ spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
+ SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT,
+ SPI_CR1_LSBFIRST);
+ spi_write(SPI1, 0x55); // 8-bit write
+ spi_write(SPI1, 0xaa88); // 16-bit write
+ reg8 = spi_read(SPI1); // 8-bit read
+ reg16 = spi_read(SPI1); // 16-bit read
+@endcode
+
+@todo need additional functions to aid ISRs in retrieving status
+
+*/
+
+/*
+ * 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/>.
+ */
+
+#include <libopencm3/stm32/spi.h>
+#include <libopencm3/stm32/rcc.h>
+
+/*
+ * SPI and I2S code.
+ *
+ * Examples:
+ * spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
+ * SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT,
+ * SPI_CR1_LSBFIRST);
+ * spi_write(SPI1, 0x55); // 8-bit write
+ * spi_write(SPI1, 0xaa88); // 16-bit write
+ * reg8 = spi_read(SPI1); // 8-bit read
+ * reg16 = spi_read(SPI1); // 16-bit read
+ */
+
+/**@{*/
+
+/*---------------------------------------------------------------------------*/
+/** @brief Configure the SPI as Master.
+
+The SPI peripheral is configured as a master with communication parameters
+baudrate, data format 8/16 bits, frame format lsb/msb first, clock polarity
+and phase. The SPI enable, CRC enable and CRC next controls are not affected.
+These must be controlled separately.
+
+@todo NSS pin handling.
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+@param[in] br Unsigned int32. Baudrate @ref spi_baudrate.
+@param[in] cpol Unsigned int32. Clock polarity @ref spi_cpol.
+@param[in] cpha Unsigned int32. Clock Phase @ref spi_cpha.
+@param[in] dff Unsigned int32. Data frame format 8/16 bits @ref spi_dff.
+@param[in] lsbfirst Unsigned int32. Frame format lsb/msb first @ref
+spi_lsbfirst.
+@returns int. Error code.
+*/
+
+int spi_init_master(uint32_t spi, uint32_t br, uint32_t cpol, uint32_t cpha,
+ uint32_t dff, uint32_t lsbfirst)
+{
+ uint32_t reg32 = SPI_CR1(spi);
+
+ /* Reset all bits omitting SPE, CRCEN and CRCNEXT bits. */
+ reg32 &= SPI_CR1_SPE | SPI_CR1_CRCEN | SPI_CR1_CRCNEXT;
+
+ reg32 |= SPI_CR1_MSTR; /* Configure SPI as master. */
+
+ reg32 |= br; /* Set baud rate bits. */
+ reg32 |= cpol; /* Set CPOL value. */
+ reg32 |= cpha; /* Set CPHA value. */
+ reg32 |= dff; /* Set data format (8 or 16 bits). */
+ reg32 |= lsbfirst; /* Set frame format (LSB- or MSB-first). */
+
+ /* TODO: NSS pin handling. */
+
+ SPI_CR1(spi) = reg32;
+
+ return 0; /* TODO */
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set Data Frame Format to 8 bits
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_dff_8bit(uint32_t spi)
+{
+ SPI_CR1(spi) &= ~SPI_CR1_DFF;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief SPI Set Data Frame Format to 16 bits
+
+@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
+*/
+
+void spi_set_dff_16bit(uint32_t spi)
+{
+ SPI_CR1(spi) |= SPI_CR1_DFF;
+}
+
+/**@}*/
diff --git a/libopencm3/lib/stm32/common/timer_common_all.c b/libopencm3/lib/stm32/common/timer_common_all.c
new file mode 100644
index 0000000..a1a4380
--- /dev/null
+++ b/libopencm3/lib/stm32/common/timer_common_all.c
@@ -0,0 +1,2177 @@
+/** @addtogroup timer_file
+
+@author @htmlonly &copy; @endhtmlonly 2010
+Edward Cheeseman <evbuilder@users.sourceforge.org>
+@author @htmlonly &copy; @endhtmlonly 2011
+Stephen Caudle <scaudle@doceme.com>
+
+@section tim_common Notes for All Timers
+
+This library supports the General Purpose and Advanced Control Timers for
+the STM32 series of ARM Cortex Microcontrollers by ST Microelectronics.
+
+The STM32 series have four general purpose timers (2-5), while some have
+an additional two advanced timers (1,8), and some have two basic timers (6,7).
+Some of the larger devices have additional general purpose timers (9-14).
+
+@todo Add timer DMA burst settings
+
+@section tim_api_ex Basic TIMER handling API.
+
+Enable the timer clock first. The timer mode sets the clock division ratio, the
+count alignment (edge or centred) and count direction. Finally enable the
+timer.
+
+The timer output compare block produces a signal that can be configured for
+output to a pin or passed to other peripherals for use as a trigger. In all
+cases the output compare mode must be set to define how the output responds to
+a compare match, and the output must be enabled. If output to a pin is
+required, enable the appropriate GPIO clock and set the pin to alternate output
+mode.
+
+Example: Timer 2 with 2x clock divide, edge aligned and up counting.
+@code
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_TIM2EN);
+ timer_reset(TIM2);
+ timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT_MUL_2,
+ TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
+ ...
+ timer_set_period(TIM2, 1000);
+ timer_enable_counter(TIM2);
+@endcode
+Example: Timer 1 with PWM output, no clock divide and centre alignment. Set the
+Output Compare mode to PWM and enable the output of channel 1. Note that for
+the advanced timers the break functionality must be enabled before the signal
+will appear at the output, even though break is not being used. This is in
+addition to the normal output enable. Enable the alternate function clock (APB2
+only) and port A clock. Set ports A8 and A9 (timer 1 channel 1 compare outputs)
+to alternate function push-pull outputs where the PWM output will appear.
+
+@code
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN |
+ RCC_APB2ENR_AFIOEN);
+ gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
+ GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO8 | GPIO9);
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_TIM1EN);
+ timer_reset(TIM1);
+ timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_CENTER_1,
+ TIM_CR1_DIR_UP);
+ timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_PWM2);
+ timer_enable_oc_output(TIM1, TIM_OC1);
+ timer_enable_break_main_output(TIM1);
+ timer_set_oc_value(TIM1, TIM_OC1, 200);
+ timer_set_period(TIM1, 1000);
+ timer_enable_counter(TIM1);
+@endcode
+
+@todo input capture example
+
+*/
+
+/*
+ * 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/>.
+ */
+
+/*
+ * Basic TIMER handling API.
+ *
+ * Examples:
+ * timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT_MUL_2,
+ * TIM_CR1_CMS_CENTRE_3, TIM_CR1_DIR_UP);
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/timer.h>
+#include <libopencm3/stm32/rcc.h>
+
+#define ADVANCED_TIMERS (defined(TIM1_BASE) || defined(TIM8_BASE))
+
+#if defined(TIM8)
+#define TIMER_IS_ADVANCED(periph) ((periph == TIM1) || (periph == TIM8))
+#else
+#define TIMER_IS_ADVANCED(periph) (periph == TIM1)
+#endif
+
+/*---------------------------------------------------------------------------*/
+/** @brief Reset a Timer.
+
+The counter and all its associated configuration registers are placed in the
+reset condition. The reset is effected via the RCC peripheral reset system.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+ tim_reg_base (TIM9 .. TIM14 not yet supported here).
+*/
+
+void timer_reset(uint32_t timer_peripheral)
+{
+ switch (timer_peripheral) {
+#if defined(TIM1_BASE)
+ case TIM1:
+ rcc_periph_reset_pulse(RST_TIM1);
+ break;
+#endif
+ case TIM2:
+ rcc_periph_reset_pulse(RST_TIM2);
+ break;
+ case TIM3:
+ rcc_periph_reset_pulse(RST_TIM3);
+ break;
+#if defined(TIM4_BASE)
+ case TIM4:
+ rcc_periph_reset_pulse(RST_TIM4);
+ break;
+#endif
+#if defined(TIM5_BASE)
+ case TIM5:
+ rcc_periph_reset_pulse(RST_TIM5);
+ break;
+#endif
+ case TIM6:
+ rcc_periph_reset_pulse(RST_TIM6);
+ break;
+ case TIM7:
+ rcc_periph_reset_pulse(RST_TIM7);
+ break;
+#if defined(TIM8_BASE)
+ case TIM8:
+ rcc_periph_reset_pulse(RST_TIM8);
+ break;
+#endif
+/* These timers are not supported in libopencm3 yet */
+/*
+ case TIM9:
+ rcc_periph_reset_pulse(RST_TIM9);
+ break;
+ case TIM10:
+ rcc_periph_reset_pulse(RST_TIM10);
+ break;
+ case TIM11:
+ rcc_periph_reset_pulse(RST_TIM11);
+ break;
+ case TIM12:
+ rcc_periph_reset_pulse(RST_TIM12);
+ break;
+ case TIM13:
+ rcc_periph_reset_pulse(RST_TIM13);
+ break;
+ case TIM14:
+ rcc_periph_reset_pulse(RST_TIM14);
+ break;
+*/
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Interrupts for a Timer
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] irq Unsigned int32. @ref tim_irq_enable. Logical OR of all interrupt
+enable bits to be set
+*/
+
+void timer_enable_irq(uint32_t timer_peripheral, uint32_t irq)
+{
+ TIM_DIER(timer_peripheral) |= irq;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Interrupts for a Timer.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] irq Unsigned int32. @ref tim_irq_enable. Logical OR of all interrupt
+enable bits to be cleared
+*/
+
+void timer_disable_irq(uint32_t timer_peripheral, uint32_t irq)
+{
+ TIM_DIER(timer_peripheral) &= ~irq;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Return Interrupt Source.
+
+Returns true if the specified interrupt flag (UIF, TIF or CCxIF, with BIF or
+COMIF for advanced timers) was set and the interrupt was enabled. If the
+specified flag is not an interrupt flag, the function returns false.
+
+@todo Timers 6-7, 9-14 have fewer interrupts, but invalid flags are not caught
+here.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] flag Unsigned int32. Status register flag @ref tim_sr_values.
+@returns boolean: flag set.
+*/
+
+bool timer_interrupt_source(uint32_t timer_peripheral, uint32_t flag)
+{
+/* flag not set or interrupt disabled or not an interrupt source */
+ if (((TIM_SR(timer_peripheral) &
+ TIM_DIER(timer_peripheral) & flag) == 0) ||
+ (flag > TIM_SR_BIF)) {
+ return false;
+ }
+/* Only an interrupt source for advanced timers */
+#if ADVANCED_TIMERS
+ if ((flag == TIM_SR_BIF) || (flag == TIM_SR_COMIF)) {
+ return TIMER_IS_ADVANCED(timer_peripheral);
+ }
+#endif
+ return true;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Read a Status Flag.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] flag Unsigned int32. Status register flag @ref tim_sr_values.
+@returns boolean: flag set.
+*/
+
+bool timer_get_flag(uint32_t timer_peripheral, uint32_t flag)
+{
+ if ((TIM_SR(timer_peripheral) & flag) != 0) {
+ return true;
+ }
+
+ return false;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Clear a Status Flag.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] flag Unsigned int32. @ref tim_sr_values. Status register flag.
+*/
+
+void timer_clear_flag(uint32_t timer_peripheral, uint32_t flag)
+{
+ TIM_SR(timer_peripheral) &= ~flag;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Timer Mode.
+
+The modes are:
+
+@li Clock divider ratio (to form the sampling clock for the input filters,
+and the dead-time clock in the advanced timers 1 and 8)
+@li Edge/centre alignment
+@li Count direction
+
+The alignment and count direction are effective only for timers 1 to 5 and 8
+while the clock divider ratio is effective for all timers except 6,7
+The remaining timers are limited hardware timers which do not support these mode
+settings.
+
+@note: When center alignment mode is selected, count direction is controlled by
+hardware and cannot be written. The count direction setting has no effect
+in this case.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base (TIM1, TIM2 ... TIM5, TIM8)
+@param[in] clock_div Unsigned int32. Clock Divider Ratio in bits 8,9: @ref
+tim_x_cr1_cdr
+@param[in] alignment Unsigned int32. Alignment bits in 5,6: @ref tim_x_cr1_cms
+@param[in] direction Unsigned int32. Count direction in bit 4,: @ref
+tim_x_cr1_dir
+*/
+
+void timer_set_mode(uint32_t timer_peripheral, uint32_t clock_div,
+ uint32_t alignment, uint32_t direction)
+{
+ uint32_t cr1;
+
+ cr1 = TIM_CR1(timer_peripheral);
+
+ cr1 &= ~(TIM_CR1_CKD_CK_INT_MASK | TIM_CR1_CMS_MASK | TIM_CR1_DIR_DOWN);
+
+ cr1 |= clock_div | alignment | direction;
+
+ TIM_CR1(timer_peripheral) = cr1;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Input Filter and Dead-time Clock Divider Ratio.
+
+This forms the sampling clock for the input filters and the dead-time clock
+in the advanced timers 1 and 8, by division from the timer clock.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] clock_div Unsigned int32. Clock Divider Ratio in bits 8,9: @ref
+tim_x_cr1_cdr
+*/
+
+void timer_set_clock_division(uint32_t timer_peripheral, uint32_t clock_div)
+{
+ clock_div &= TIM_CR1_CKD_CK_INT_MASK;
+ TIM_CR1(timer_peripheral) &= ~TIM_CR1_CKD_CK_INT_MASK;
+ TIM_CR1(timer_peripheral) |= clock_div;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Auto-Reload Buffering.
+
+During counter operation this causes the counter to be loaded from its
+auto-reload register only at the next update event.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_enable_preload(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) |= TIM_CR1_ARPE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Auto-Reload Buffering.
+
+This causes the counter to be loaded immediately with a new count value when the
+auto-reload register is written, so that the new value becomes effective for the
+current count cycle rather than for the cycle following an update event.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_disable_preload(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) &= ~TIM_CR1_ARPE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Specify the counter alignment mode.
+
+The mode can be edge aligned or centered.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] alignment Unsigned int32. Alignment bits in 5,6: @ref tim_x_cr1_cms
+*/
+
+void timer_set_alignment(uint32_t timer_peripheral, uint32_t alignment)
+{
+ alignment &= TIM_CR1_CMS_MASK;
+ TIM_CR1(timer_peripheral) &= ~TIM_CR1_CMS_MASK;
+ TIM_CR1(timer_peripheral) |= alignment;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Timer to Count Up.
+
+This has no effect if the timer is set to center aligned.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_direction_up(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) &= ~TIM_CR1_DIR_DOWN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Timer to Count Down.
+
+This has no effect if the timer is set to center aligned.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_direction_down(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) |= TIM_CR1_DIR_DOWN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the Timer for One Cycle and Stop.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_one_shot_mode(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) |= TIM_CR1_OPM;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the Timer to Run Continuously.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_continuous_mode(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) &= ~TIM_CR1_OPM;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Timer to Generate Update IRQ or DMA on any Event.
+
+The events which will generate an interrupt or DMA request can be
+@li a counter underflow/overflow,
+@li a forced update,
+@li an event from the slave mode controller.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_update_on_any(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) &= ~TIM_CR1_URS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Timer to Generate Update IRQ or DMA only from Under/Overflow
+Events.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_update_on_overflow(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) |= TIM_CR1_URS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Timer Update Events.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_enable_update_event(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) &= ~TIM_CR1_UDIS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Timer Update Events.
+
+Update events are not generated and the shadow registers keep their values.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_disable_update_event(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) |= TIM_CR1_UDIS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable the timer to start counting.
+
+This should be called after the timer initial configuration has been completed.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_enable_counter(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) |= TIM_CR1_CEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Stop the timer from counting.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_disable_counter(uint32_t timer_peripheral)
+{
+ TIM_CR1(timer_peripheral) &= ~TIM_CR1_CEN;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Timer Output Idle States High.
+
+This determines the value of the timer output compare when it enters idle state.
+
+@sa @ref timer_set_oc_idle_state_set
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] outputs Unsigned int32. Timer Output Idle State Controls @ref
+tim_x_cr2_ois. If several settings are to be made, use the logical OR of the
+output control values.
+*/
+
+void timer_set_output_idle_state(uint32_t timer_peripheral, uint32_t outputs)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_CR2(timer_peripheral) |= outputs & TIM_CR2_OIS_MASK;
+ }
+#else
+ (void)timer_peripheral;
+ (void)outputs;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Timer Output Idle States Low.
+
+This determines the value of the timer output compare when it enters idle state.
+
+@sa @ref timer_set_oc_idle_state_unset
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] outputs Unsigned int32. Timer Output Idle State Controls @ref
+tim_x_cr2_ois
+*/
+
+void timer_reset_output_idle_state(uint32_t timer_peripheral, uint32_t outputs)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_CR2(timer_peripheral) &= ~(outputs & TIM_CR2_OIS_MASK);
+ }
+#else
+ (void)timer_peripheral;
+ (void)outputs;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Timer 1 Input to XOR of Three Channels.
+
+The first timer capture input is formed from the XOR of the first three timer
+input channels 1, 2, 3.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_set_ti1_ch123_xor(uint32_t timer_peripheral)
+{
+ TIM_CR2(timer_peripheral) |= TIM_CR2_TI1S;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Timer 1 Input to Channel 1.
+
+The first timer capture input is taken from the timer input channel 1 only.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_set_ti1_ch1(uint32_t timer_peripheral)
+{
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_TI1S;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Master Mode
+
+This sets the Trigger Output TRGO for synchronizing with slave timers or
+passing as an internal trigger to the ADC or DAC.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] mode Unsigned int32. Master Mode @ref tim_mastermode
+*/
+
+void timer_set_master_mode(uint32_t timer_peripheral, uint32_t mode)
+{
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_MMS_MASK;
+ TIM_CR2(timer_peripheral) |= mode;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Timer DMA Requests on Capture/Compare Events.
+
+Capture/compare events will cause DMA requests to be generated.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_set_dma_on_compare_event(uint32_t timer_peripheral)
+{
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCDS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Timer DMA Requests on Update Events.
+
+Update events will cause DMA requests to be generated.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_set_dma_on_update_event(uint32_t timer_peripheral)
+{
+ TIM_CR2(timer_peripheral) |= TIM_CR2_CCDS;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Timer Capture/Compare Control Update with Trigger.
+
+If the capture/compare control bits CCxE, CCxNE and OCxM are set to be
+preloaded, they are updated by software generating the COMG event (@ref
+timer_generate_event) or when a rising edge occurs on the trigger input TRGI.
+
+@note This setting is only valid for the advanced timer channels with
+complementary outputs.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_enable_compare_control_update_on_trigger(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_CR2(timer_peripheral) |= TIM_CR2_CCUS;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Timer Capture/Compare Control Update with Trigger.
+
+If the capture/compare control bits CCxE, CCxNE and OCxM are set to be
+preloaded, they are updated by software generating the COMG event (@ref
+timer_generate_event).
+
+@note This setting is only valid for the advanced timer channels with
+complementary outputs.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_disable_compare_control_update_on_trigger(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCUS;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Timer Capture/Compare Control Preload.
+
+The capture/compare control bits CCxE, CCxNE and OCxM are set to be preloaded
+when a COM event occurs.
+
+@note This setting is only valid for the advanced timer channels with
+complementary outputs.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_enable_preload_complementry_enable_bits(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_CR2(timer_peripheral) |= TIM_CR2_CCPC;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Timer Capture/Compare Control Preload.
+
+The capture/compare control bits CCxE, CCxNE and OCxM preload is disabled.
+
+@note This setting is only valid for the advanced timer channels with
+complementary outputs.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+*/
+
+void timer_disable_preload_complementry_enable_bits(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCPC;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Value for the Timer Prescaler.
+
+The timer clock is prescaled by the 16 bit scale value plus 1.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] value Unsigned int32. Prescaler values 0...0xFFFF.
+*/
+
+void timer_set_prescaler(uint32_t timer_peripheral, uint32_t value)
+{
+ TIM_PSC(timer_peripheral) = value;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set the Value for the Timer Repetition Counter.
+
+A timer update event is generated only after the specified number of repeat
+count cycles have been completed.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] value Unsigned int32. Repetition values 0...0xFF.
+*/
+
+void timer_set_repetition_counter(uint32_t timer_peripheral, uint32_t value)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_RCR(timer_peripheral) = value;
+ }
+#else
+ (void)timer_peripheral;
+ (void)value;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Set Period
+
+Specify the timer period in the auto-reload register.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] period Unsigned int32. Period in counter clock ticks.
+*/
+
+void timer_set_period(uint32_t timer_peripheral, uint32_t period)
+{
+ TIM_ARR(timer_peripheral) = period;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Enable the Output Compare Clear Function
+
+When this is enabled, the output compare signal is cleared when a high is
+detected on the external trigger input. This works in the output compare and
+PWM modes only (not forced mode).
+The output compare signal remains off until the next update event.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken)
+*/
+
+void timer_enable_oc_clear(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1CE;
+ break;
+ case TIM_OC2:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2CE;
+ break;
+ case TIM_OC3:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3CE;
+ break;
+ case TIM_OC4:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4CE;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as oc clear enable only applies to the whole
+ * channel.
+ */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Disable the Output Compare Clear Function
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken)
+*/
+
+void timer_disable_oc_clear(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1CE;
+ break;
+ case TIM_OC2:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2CE;
+ break;
+ case TIM_OC3:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3CE;
+ break;
+ case TIM_OC4:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4CE;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as oc clear enable only applies to the whole
+ * channel.
+ */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Enable the Output Compare Fast Mode
+
+When this is enabled, the output compare signal is forced to the compare state
+by a trigger input, independently of the compare match. This speeds up the
+setting of the output compare to 3 clock cycles as opposed to at least 5 in the
+slow mode. This works in the PWM1 and PWM2 modes only.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken)
+*/
+
+void timer_set_oc_fast_mode(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1FE;
+ break;
+ case TIM_OC2:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2FE;
+ break;
+ case TIM_OC3:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3FE;
+ break;
+ case TIM_OC4:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4FE;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as fast enable only applies to the whole channel. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Enable the Output Compare Slow Mode
+
+This disables the fast compare mode and the output compare depends on the
+counter and compare register values.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken)
+*/
+
+void timer_set_oc_slow_mode(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1FE;
+ break;
+ case TIM_OC2:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2FE;
+ break;
+ case TIM_OC3:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3FE;
+ break;
+ case TIM_OC4:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4FE;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to the whole channel. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Set Output Compare Mode
+
+Specifies how the comparator output will respond to a compare match. The mode
+can be:
+@li Frozen - the output does not respond to a match.
+@li Active - the output assumes the active state on the first match.
+@li Inactive - the output assumes the inactive state on the first match.
+@li Toggle - The output switches between active and inactive states on each
+match.
+@li Force inactive. The output is forced low regardless of the compare state.
+@li Force active. The output is forced high regardless of the compare state.
+@li PWM1 - The output is active when the counter is less than the compare
+register contents and inactive otherwise.
+@li PWM2 - The output is inactive when the counter is less than the compare
+register contents and active otherwise.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken)
+@param[in] oc_mode enum ::tim_oc_mode. OC mode designators.
+ TIM_OCM_FROZEN, TIM_OCM_ACTIVE, TIM_OCM_INACTIVE,
+ TIM_OCM_TOGGLE, TIM_OCM_FORCE_LOW, TIM_OCM_FORCE_HIGH,
+ TIM_OCM_PWM1, TIM_OCM_PWM2
+*/
+
+void timer_set_oc_mode(uint32_t timer_peripheral, enum tim_oc_id oc_id,
+ enum tim_oc_mode oc_mode)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC1S_MASK;
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_CC1S_OUT;
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1M_MASK;
+ switch (oc_mode) {
+ case TIM_OCM_FROZEN:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_FROZEN;
+ break;
+ case TIM_OCM_ACTIVE:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_ACTIVE;
+ break;
+ case TIM_OCM_INACTIVE:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_INACTIVE;
+ break;
+ case TIM_OCM_TOGGLE:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_TOGGLE;
+ break;
+ case TIM_OCM_FORCE_LOW:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_FORCE_LOW;
+ break;
+ case TIM_OCM_FORCE_HIGH:
+ TIM_CCMR1(timer_peripheral) |=
+ TIM_CCMR1_OC1M_FORCE_HIGH;
+ break;
+ case TIM_OCM_PWM1:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_PWM1;
+ break;
+ case TIM_OCM_PWM2:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_PWM2;
+ break;
+ }
+ break;
+ case TIM_OC2:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC2S_MASK;
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_CC2S_OUT;
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2M_MASK;
+ switch (oc_mode) {
+ case TIM_OCM_FROZEN:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_FROZEN;
+ break;
+ case TIM_OCM_ACTIVE:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_ACTIVE;
+ break;
+ case TIM_OCM_INACTIVE:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_INACTIVE;
+ break;
+ case TIM_OCM_TOGGLE:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_TOGGLE;
+ break;
+ case TIM_OCM_FORCE_LOW:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_FORCE_LOW;
+ break;
+ case TIM_OCM_FORCE_HIGH:
+ TIM_CCMR1(timer_peripheral) |=
+ TIM_CCMR1_OC2M_FORCE_HIGH;
+ break;
+ case TIM_OCM_PWM1:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_PWM1;
+ break;
+ case TIM_OCM_PWM2:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_PWM2;
+ break;
+ }
+ break;
+ case TIM_OC3:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_CC3S_MASK;
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_CC3S_OUT;
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3M_MASK;
+ switch (oc_mode) {
+ case TIM_OCM_FROZEN:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_FROZEN;
+ break;
+ case TIM_OCM_ACTIVE:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_ACTIVE;
+ break;
+ case TIM_OCM_INACTIVE:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_INACTIVE;
+ break;
+ case TIM_OCM_TOGGLE:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_TOGGLE;
+ break;
+ case TIM_OCM_FORCE_LOW:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_FORCE_LOW;
+ break;
+ case TIM_OCM_FORCE_HIGH:
+ TIM_CCMR2(timer_peripheral) |=
+ TIM_CCMR2_OC3M_FORCE_HIGH;
+ break;
+ case TIM_OCM_PWM1:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_PWM1;
+ break;
+ case TIM_OCM_PWM2:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_PWM2;
+ break;
+ }
+ break;
+ case TIM_OC4:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_CC4S_MASK;
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_CC4S_OUT;
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4M_MASK;
+ switch (oc_mode) {
+ case TIM_OCM_FROZEN:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_FROZEN;
+ break;
+ case TIM_OCM_ACTIVE:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_ACTIVE;
+ break;
+ case TIM_OCM_INACTIVE:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_INACTIVE;
+ break;
+ case TIM_OCM_TOGGLE:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_TOGGLE;
+ break;
+ case TIM_OCM_FORCE_LOW:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_FORCE_LOW;
+ break;
+ case TIM_OCM_FORCE_HIGH:
+ TIM_CCMR2(timer_peripheral) |=
+ TIM_CCMR2_OC4M_FORCE_HIGH;
+ break;
+ case TIM_OCM_PWM1:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_PWM1;
+ break;
+ case TIM_OCM_PWM2:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_PWM2;
+ break;
+ }
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to the whole channel. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Enable the Output Compare Preload Register
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken)
+*/
+
+void timer_enable_oc_preload(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1PE;
+ break;
+ case TIM_OC2:
+ TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2PE;
+ break;
+ case TIM_OC3:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3PE;
+ break;
+ case TIM_OC4:
+ TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4PE;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to the whole channel. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Disable the Output Compare Preload Register
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action)
+*/
+
+void timer_disable_oc_preload(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1PE;
+ break;
+ case TIM_OC2:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2PE;
+ break;
+ case TIM_OC3:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3PE;
+ break;
+ case TIM_OC4:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4PE;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to the whole channel. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Set the Output Polarity High
+
+The polarity of the channel output is set active high.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced
+ timers 1 and 8)
+*/
+
+void timer_set_oc_polarity_high(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1P;
+ break;
+ case TIM_OC2:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2P;
+ break;
+ case TIM_OC3:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3P;
+ break;
+ case TIM_OC4:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC4P;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to TIM1 and TIM8 only. */
+ break;
+ }
+
+ /* Acting for TIM1 and TIM8 only from here onwards. */
+#if ADVANCED_TIMERS
+ if (!TIMER_IS_ADVANCED(timer_peripheral)) {
+ return;
+ }
+#else
+ return;
+#endif
+
+ switch (oc_id) {
+ case TIM_OC1N:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1NP;
+ break;
+ case TIM_OC2N:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2NP;
+ break;
+ case TIM_OC3N:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3NP;
+ break;
+ case TIM_OC1:
+ case TIM_OC2:
+ case TIM_OC3:
+ case TIM_OC4:
+ /* Ignoring as this option was already set above. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Set the Output Polarity Low
+
+The polarity of the channel output is set active low.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced
+ timers 1 and 8)
+*/
+
+void timer_set_oc_polarity_low(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC1P;
+ break;
+ case TIM_OC2:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC2P;
+ break;
+ case TIM_OC3:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC3P;
+ break;
+ case TIM_OC4:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC4P;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to TIM1 and TIM8 only. */
+ break;
+ }
+
+ /* Acting for TIM1 and TIM8 only from here onwards. */
+#if ADVANCED_TIMERS
+ if (!TIMER_IS_ADVANCED(timer_peripheral)) {
+ return;
+ }
+#else
+ return;
+#endif
+
+ switch (oc_id) {
+ case TIM_OC1N:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC1NP;
+ break;
+ case TIM_OC2N:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC2NP;
+ break;
+ case TIM_OC3N:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC3NP;
+ break;
+ case TIM_OC1:
+ case TIM_OC2:
+ case TIM_OC3:
+ case TIM_OC4:
+ /* Ignoring as this option was already set above. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Enable the Output Compare
+
+The channel output compare functionality is enabled.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced
+ timers 1 and 8)
+*/
+
+void timer_enable_oc_output(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC1E;
+ break;
+ case TIM_OC2:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC2E;
+ break;
+ case TIM_OC3:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC3E;
+ break;
+ case TIM_OC4:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC4E;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to TIM1 and TIM8 only. */
+ break;
+ }
+
+ /* Acting for TIM1 and TIM8 only from here onwards. */
+#if ADVANCED_TIMERS
+ if (!TIMER_IS_ADVANCED(timer_peripheral)) {
+ return;
+ }
+#else
+ return;
+#endif
+
+ switch (oc_id) {
+ case TIM_OC1N:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC1NE;
+ break;
+ case TIM_OC2N:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC2NE;
+ break;
+ case TIM_OC3N:
+ TIM_CCER(timer_peripheral) |= TIM_CCER_CC3NE;
+ break;
+ case TIM_OC1:
+ case TIM_OC2:
+ case TIM_OC3:
+ case TIM_OC4:
+ /* Ignoring as this option was already set above. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Disable the Output Compare
+
+The channel output compare functionality is disabled.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced
+ timers 1 and 8)
+*/
+
+void timer_disable_oc_output(uint32_t timer_peripheral, enum tim_oc_id oc_id)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1E;
+ break;
+ case TIM_OC2:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2E;
+ break;
+ case TIM_OC3:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3E;
+ break;
+ case TIM_OC4:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC4E;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to TIM1 and TIM8 only. */
+ break;
+ }
+
+ /* Acting for TIM1 and TIM8 only from here onwards. */
+#if ADVANCED_TIMERS
+ if (!TIMER_IS_ADVANCED(timer_peripheral)) {
+ return;
+ }
+#else
+ return;
+#endif
+
+ switch (oc_id) {
+ case TIM_OC1N:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1NE;
+ break;
+ case TIM_OC2N:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2NE;
+ break;
+ case TIM_OC3N:
+ TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3NE;
+ break;
+ case TIM_OC1:
+ case TIM_OC2:
+ case TIM_OC3:
+ case TIM_OC4:
+ /* Ignoring as this option was already set above. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer set Output Compare Idle State High
+
+@sa Similar function suitable for multiple OC idle state settings
+@ref timer_set_output_idle_state
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced
+ timers 1 and 8)
+*/
+
+void timer_set_oc_idle_state_set(uint32_t timer_peripheral,
+ enum tim_oc_id oc_id)
+{
+#if ADVANCED_TIMERS
+ /* Acting for TIM1 and TIM8 only. */
+ if (!TIMER_IS_ADVANCED(timer_peripheral)) {
+ return;
+ }
+
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CR2(timer_peripheral) |= TIM_CR2_OIS1;
+ break;
+ case TIM_OC1N:
+ TIM_CR2(timer_peripheral) |= TIM_CR2_OIS1N;
+ break;
+ case TIM_OC2:
+ TIM_CR2(timer_peripheral) |= TIM_CR2_OIS2;
+ break;
+ case TIM_OC2N:
+ TIM_CR2(timer_peripheral) |= TIM_CR2_OIS2N;
+ break;
+ case TIM_OC3:
+ TIM_CR2(timer_peripheral) |= TIM_CR2_OIS3;
+ break;
+ case TIM_OC3N:
+ TIM_CR2(timer_peripheral) |= TIM_CR2_OIS3N;
+ break;
+ case TIM_OC4:
+ TIM_CR2(timer_peripheral) |= TIM_CR2_OIS4;
+ break;
+ }
+#else
+ (void)timer_peripheral;
+ (void)oc_id;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Set Output Compare Idle State Low
+
+@sa Similar function suitable for multiple OC idle state settings
+@ref timer_reset_output_idle_state
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+tim_reg_base
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (only for advanced
+ timers 1 and 8)
+*/
+
+void timer_set_oc_idle_state_unset(uint32_t timer_peripheral,
+ enum tim_oc_id oc_id)
+{
+#if ADVANCED_TIMERS
+ /* Acting for TIM1 and TIM8 only. */
+ if (!TIMER_IS_ADVANCED(timer_peripheral)) {
+ return;
+ }
+
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS1;
+ break;
+ case TIM_OC1N:
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS1N;
+ break;
+ case TIM_OC2:
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS2;
+ break;
+ case TIM_OC2N:
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS2N;
+ break;
+ case TIM_OC3:
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS3;
+ break;
+ case TIM_OC3N:
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS3N;
+ break;
+ case TIM_OC4:
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS4;
+ break;
+ }
+#else
+ (void)timer_peripheral;
+ (void)oc_id;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Timer Set Output Compare Value
+
+This is a convenience function to set the OC preload register value for loading
+to the compare register.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base @ref
+ tim_reg_base (TIM9 .. TIM14 not yet supported here).
+@param[in] oc_id enum ::tim_oc_id OC channel designators
+ TIM_OCx where x=1..4, TIM_OCxN where x=1..3 (no action taken)
+@param[in] value Unsigned int32. Compare value.
+*/
+
+void timer_set_oc_value(uint32_t timer_peripheral, enum tim_oc_id oc_id,
+ uint32_t value)
+{
+ switch (oc_id) {
+ case TIM_OC1:
+ TIM_CCR1(timer_peripheral) = value;
+ break;
+ case TIM_OC2:
+ TIM_CCR2(timer_peripheral) = value;
+ break;
+ case TIM_OC3:
+ TIM_CCR3(timer_peripheral) = value;
+ break;
+ case TIM_OC4:
+ TIM_CCR4(timer_peripheral) = value;
+ break;
+ case TIM_OC1N:
+ case TIM_OC2N:
+ case TIM_OC3N:
+ /* Ignoring as this option applies to the whole channel. */
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Output in Break
+
+Enables the output in the Break feature of an advanced timer. This does not
+enable the break functionality itself but only sets the Master Output Enable in
+the Break and Deadtime Register.
+
+@note This setting is only valid for the advanced timers.
+
+@note It is necessary to call this function to enable the output on an advanced
+timer <b>even if break or deadtime features are not being used</b>.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_enable_break_main_output(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) |= TIM_BDTR_MOE;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Output in Break
+
+Disables the output in the Break feature of an advanced timer. This clears
+the Master Output Enable in the Break and Deadtime Register.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_disable_break_main_output(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_MOE;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Automatic Output in Break
+
+Enables the automatic output feature of the Break function of an advanced
+timer so that the output is re-enabled at the next update event following a
+break event.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_enable_break_automatic_output(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) |= TIM_BDTR_AOE;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Automatic Output in Break
+
+Disables the automatic output feature of the Break function of an advanced
+timer so that the output is re-enabled at the next update event following a
+break event.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_disable_break_automatic_output(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_AOE;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Activate Break when Input High
+
+Sets the break function to activate when the break input becomes high.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_set_break_polarity_high(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) |= TIM_BDTR_BKP;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Activate Break when Input Low
+
+Sets the break function to activate when the break input becomes low.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_set_break_polarity_low(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_BKP;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Break
+
+Enables the break function of an advanced timer.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_enable_break(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) |= TIM_BDTR_BKE;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Break
+
+Disables the break function of an advanced timer.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_disable_break(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_BKE;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Off-State in Run Mode
+
+Enables the off-state in run mode for the break function of an advanced
+timer in which the complementary outputs have been configured. It has no effect
+if no complementary output is present. When the capture-compare output is
+disabled while the complementary output is enabled, the output is set to its
+inactive level as defined by the output polarity.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_set_enabled_off_state_in_run_mode(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) |= TIM_BDTR_OSSR;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Off-State in Run Mode
+
+Disables the off-state in run mode for the break function of an advanced
+timer in which the complementary outputs have been configured. It has no effect
+if no complementary output is present. When the capture-compare output is
+disabled, the output is also disabled.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_set_disabled_off_state_in_run_mode(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_OSSR;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Off-State in Idle Mode
+
+Enables the off-state in idle mode for the break function of an advanced
+timer. When the master output is disabled the output is set to its
+inactive level as defined by the output polarity.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_set_enabled_off_state_in_idle_mode(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) |= TIM_BDTR_OSSI;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Off-State in Idle Mode
+
+Disables the off-state in idle mode for the break function of an advanced
+timer. When the master output is disabled the output is also disabled.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+*/
+
+void timer_set_disabled_off_state_in_idle_mode(uint32_t timer_peripheral)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_OSSI;
+ }
+#else
+ (void)timer_peripheral;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Lock Bits
+
+Set the lock bits for an advanced timer. Three levels of lock providing
+protection against software errors. Once written they cannot be changed until a
+timer reset has occurred.
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+@param[in] lock Unsigned int32. Lock specification @ref tim_lock
+*/
+
+void timer_set_break_lock(uint32_t timer_peripheral, uint32_t lock)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) |= lock;
+ }
+#else
+ (void)timer_peripheral;
+ (void)lock;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Deadtime
+
+The deadtime and sampling clock (DTSC) is set in the clock division ratio part
+of the timer mode settings. The deadtime count is an 8 bit value defined in
+terms of the number of DTSC cycles:
+
+@li Bit 7 = 0, deadtime = bits(6:0)
+@li Bits 7:6 = 10, deadtime = 2x(64+bits(5:0))
+@li Bits 7:5 = 110, deadtime = 8x(32+bits(5:0))
+@li Bits 7:5 = 111, deadtime = 16x(32+bits(5:0))
+
+@note This setting is only valid for the advanced timers.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base TIM1 or
+TIM8
+@param[in] deadtime Unsigned int32. Deadtime count specification as defined
+above.
+*/
+
+void timer_set_deadtime(uint32_t timer_peripheral, uint32_t deadtime)
+{
+#if ADVANCED_TIMERS
+ if (TIMER_IS_ADVANCED(timer_peripheral)) {
+ TIM_BDTR(timer_peripheral) |= deadtime;
+ }
+#else
+ (void)timer_peripheral;
+ (void)deadtime;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Force generate a timer event.
+
+The event specification consists of 8 possible events that can be forced on the
+timer. The forced events are automatically cleared by hardware. The UG event is
+useful to cause shadow registers to be preloaded before the timer is started to
+avoid uncertainties in the first cycle in case an update event may never be
+generated.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] event Unsigned int32. Event specification @ref tim_event_gen
+*/
+
+void timer_generate_event(uint32_t timer_peripheral, uint32_t event)
+{
+ TIM_EGR(timer_peripheral) |= event;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Read Counter
+
+Read back the value of a timer's counter register contents
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@returns Unsigned int32. Counter value.
+*/
+
+uint32_t timer_get_counter(uint32_t timer_peripheral)
+{
+ return TIM_CNT(timer_peripheral);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Counter
+
+Set the value of a timer's counter register contents.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] count Unsigned int32. Counter value.
+*/
+
+void timer_set_counter(uint32_t timer_peripheral, uint32_t count)
+{
+ TIM_CNT(timer_peripheral) = count;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Input Capture Filter Parameters
+
+Set the input filter parameters for an input channel, specifying:
+@li the frequency of sampling from the Deadtime and Sampling clock
+(@see @ref timer_set_clock_division)
+@li the number of events that must occur before a transition is considered
+valid.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] ic ::tim_ic_id. Input Capture channel designator.
+@param[in] flt ::tim_ic_filter. Input Capture Filter identifier.
+*/
+
+void timer_ic_set_filter(uint32_t timer_peripheral, enum tim_ic_id ic,
+ enum tim_ic_filter flt)
+{
+ switch (ic) {
+ case TIM_IC1:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_IC1F_MASK;
+ TIM_CCMR1(timer_peripheral) |= flt << 4;
+ break;
+ case TIM_IC2:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_IC2F_MASK;
+ TIM_CCMR1(timer_peripheral) |= flt << 12;
+ break;
+ case TIM_IC3:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_IC3F_MASK;
+ TIM_CCMR2(timer_peripheral) |= flt << 4;
+ break;
+ case TIM_IC4:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_IC4F_MASK;
+ TIM_CCMR2(timer_peripheral) |= flt << 12;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Input Capture Prescaler
+
+Set the number of events between each capture.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] ic ::tim_ic_id. Input Capture channel designator.
+@param[in] psc ::tim_ic_psc. Input Capture sample clock prescaler.
+*/
+
+void timer_ic_set_prescaler(uint32_t timer_peripheral, enum tim_ic_id ic,
+ enum tim_ic_psc psc)
+{
+ switch (ic) {
+ case TIM_IC1:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_IC1PSC_MASK;
+ TIM_CCMR1(timer_peripheral) |= psc << 2;
+ break;
+ case TIM_IC2:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_IC2PSC_MASK;
+ TIM_CCMR1(timer_peripheral) |= psc << 10;
+ break;
+ case TIM_IC3:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_IC3PSC_MASK;
+ TIM_CCMR2(timer_peripheral) |= psc << 2;
+ break;
+ case TIM_IC4:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_IC4PSC_MASK;
+ TIM_CCMR2(timer_peripheral) |= psc << 10;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Capture/Compare Channel Direction/Input
+
+The Capture/Compare channel is defined as output (compare) or input with the
+input mapping specified:
+
+@li channel is configured as output
+@li channel is configured as input and mapped on corresponding input
+@li channel is configured as input and mapped on alternate input
+(TI2 for channel 1, TI1 for channel 2, TI4 for channel 3, TI3 for channel 4)
+@li channel is configured as input and is mapped on TRC (requires an
+internal trigger input selected through TS bit
+
+@note not all combinations of the input and channel are valid, see datasheets.
+@note these parameters are writable only when the channel is off.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] ic ::tim_ic_id. Input Capture channel designator.
+@param[in] in ::tim_ic_input. Input Capture channel direction and source input.
+*/
+
+void timer_ic_set_input(uint32_t timer_peripheral, enum tim_ic_id ic,
+ enum tim_ic_input in)
+{
+ in &= 3;
+
+ if (((ic == TIM_IC2) || (ic == TIM_IC4)) &&
+ ((in == TIM_IC_IN_TI1) || (in == TIM_IC_IN_TI2))) {
+ /* Input select bits are flipped for these combinations */
+ in ^= 3;
+ }
+
+ switch (ic) {
+ case TIM_IC1:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC1S_MASK;
+ TIM_CCMR1(timer_peripheral) |= in;
+ break;
+ case TIM_IC2:
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC2S_MASK;
+ TIM_CCMR1(timer_peripheral) |= in << 8;
+ break;
+ case TIM_IC3:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_CC3S_MASK;
+ TIM_CCMR2(timer_peripheral) |= in;
+ break;
+ case TIM_IC4:
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_CC4S_MASK;
+ TIM_CCMR2(timer_peripheral) |= in << 8;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Enable Timer Input Capture
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] ic ::tim_ic_id. Input Capture channel designator.
+*/
+
+void timer_ic_enable(uint32_t timer_peripheral, enum tim_ic_id ic)
+{
+ TIM_CCER(timer_peripheral) |= (0x1 << (ic * 4));
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Disable Timer Input Capture
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] ic ::tim_ic_id. Input Capture channel designator.
+*/
+
+void timer_ic_disable(uint32_t timer_peripheral, enum tim_ic_id ic)
+{
+ TIM_CCER(timer_peripheral) &= ~(0x1 << (ic * 4));
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set External Trigger Filter Parameters for Slave
+
+Set the input filter parameters for the external trigger, specifying:
+@li the frequency of sampling from the Deadtime and Sampling clock
+(@see @ref timer_set_clock_division)
+@li the number of events that must occur before a transition is considered
+valid.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] flt ::tim_ic_filter. Input Capture Filter identifier.
+*/
+
+void timer_slave_set_filter(uint32_t timer_peripheral, enum tim_ic_filter flt)
+{
+ TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_ETF_MASK;
+ TIM_SMCR(timer_peripheral) |= flt << 8;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set External Trigger Prescaler for Slave
+
+Set the external trigger frequency division ratio.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] psc ::tim_ic_psc. Input Capture sample clock prescaler.
+*/
+
+void timer_slave_set_prescaler(uint32_t timer_peripheral, enum tim_ic_psc psc)
+{
+ TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_ETPS_MASK;
+ TIM_SMCR(timer_peripheral) |= psc << 12;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set External Trigger Polarity for Slave
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] pol ::tim_et_pol. Slave External Trigger polarity.
+*/
+
+void timer_slave_set_polarity(uint32_t timer_peripheral, enum tim_et_pol pol)
+{
+ if (pol) {
+ TIM_SMCR(timer_peripheral) |= TIM_SMCR_ETP;
+ } else {
+ TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_ETP;
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Slave Mode
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] mode Unsigned int8. Slave mode @ref tim_sms
+*/
+
+void timer_slave_set_mode(uint32_t timer_peripheral, uint8_t mode)
+{
+ TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_SMS_MASK;
+ TIM_SMCR(timer_peripheral) |= mode;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Set Slave Trigger Source
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] trigger Unsigned int8. Slave trigger source @ref tim_ts
+*/
+
+void timer_slave_set_trigger(uint32_t timer_peripheral, uint8_t trigger)
+{
+ TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_TS_MASK;
+ TIM_SMCR(timer_peripheral) |= trigger;
+}
+
+/* TODO Timer DMA burst */
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/timer_common_f234.c b/libopencm3/lib/stm32/common/timer_common_f234.c
new file mode 100644
index 0000000..1506408
--- /dev/null
+++ b/libopencm3/lib/stm32/common/timer_common_f234.c
@@ -0,0 +1,58 @@
+/** @addtogroup timer_file
+
+*/
+
+/*
+ * 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 Input Polarity
+
+The timer channel must be set to input capture mode.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] ic ::tim_ic_id. Input Capture channel designator.
+@param[in] pol ::tim_ic_pol. Input Capture polarity control.
+*/
+
+void timer_ic_set_polarity(uint32_t timer_peripheral, enum tim_ic_id ic,
+ enum tim_ic_pol pol)
+{
+ /* Clear CCxP and CCxNP to zero. For both edge trigger both fields are
+ * set. Case 10 is invalid.
+ */
+ TIM_CCER(timer_peripheral) &= ~(0xa << (ic * 4));
+ switch (pol) {
+ case TIM_IC_RISING: /* 00 */
+ break;
+ case TIM_IC_BOTH: /* 11 */
+ TIM_CCER(timer_peripheral) |= (0xa << (ic * 4));
+ break;
+ case TIM_IC_FALLING: /* 01 */
+ TIM_CCER(timer_peripheral) |= (0x2 << (ic * 4));
+ }
+}
+/**@}*/
+
+
diff --git a/libopencm3/lib/stm32/common/timer_common_f24.c b/libopencm3/lib/stm32/common/timer_common_f24.c
new file mode 100644
index 0000000..ce1c1e3
--- /dev/null
+++ b/libopencm3/lib/stm32/common/timer_common_f24.c
@@ -0,0 +1,53 @@
+/** @addtogroup timer_file
+
+*/
+
+/*
+ * 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 TIM5, used for trigger remapping on TIM2,
+and similarly for TIM5 for oscillator calibration purposes.
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@returns Unsigned int32. Option flags TIM2: @ref tim2_opt_trigger_remap, TIM5:
+@ref tim5_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 == TIM5) {
+ TIM_OR(timer_peripheral) &= ~TIM5_OR_TI4_RMP_MASK;
+ TIM_OR(timer_peripheral) |= option;
+ }
+}
+
+/**@}*/
+
+
diff --git a/libopencm3/lib/stm32/common/usart_common_all.c b/libopencm3/lib/stm32/common/usart_common_all.c
new file mode 100644
index 0000000..43fd199
--- /dev/null
+++ b/libopencm3/lib/stm32/common/usart_common_all.c
@@ -0,0 +1,367 @@
+/** @addtogroup usart_file
+
+@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
+
+This library supports the USART/UART in the STM32F series
+of ARM Cortex Microcontrollers by ST Microelectronics.
+
+Devices can have up to 3 USARTs and 2 UARTs.
+
+*/
+
+/*
+ * 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/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/usart.h>
+#include <libopencm3/stm32/rcc.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Baudrate.
+
+The baud rate is computed from the APB high-speed prescaler clock (for
+USART1/6) or the APB low-speed prescaler clock (for other USARTs). These values
+must be correctly set before calling this function (refer to the
+rcc_clock_setup-* functions in RCC).
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] baud unsigned 32 bit. Baud rate specified in Hz.
+*/
+
+void usart_set_baudrate(uint32_t usart, uint32_t baud)
+{
+ uint32_t clock = rcc_ppre1_frequency;
+
+#if defined STM32F2 || defined STM32F4
+ if ((usart == USART1) ||
+ (usart == USART6)) {
+ clock = rcc_ppre2_frequency;
+ }
+#else
+ if (usart == USART1) {
+ clock = rcc_ppre2_frequency;
+ }
+#endif
+
+ /*
+ * Yes it is as simple as that. The reference manual is
+ * talking about fractional calculation but it seems to be only
+ * marketting babble to sound awesome. It is nothing else but a
+ * simple divider to generate the correct baudrate.
+ *
+ * Note: We round() the value rather than floor()ing it, for more
+ * accurate divisor selection.
+ */
+ USART_BRR(usart) = ((2 * clock) + baud) / (2 * baud);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Word Length.
+
+The word length is set to 8 or 9 bits. Note that the last bit will be a parity
+bit if parity is enabled, in which case the data length will be 7 or 8 bits
+respectively.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] bits unsigned 32 bit. Word length in bits 8 or 9.
+*/
+
+void usart_set_databits(uint32_t usart, uint32_t bits)
+{
+ if (bits == 8) {
+ USART_CR1(usart) &= ~USART_CR1_M; /* 8 data bits */
+ } else {
+ USART_CR1(usart) |= USART_CR1_M; /* 9 data bits */
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Stop Bit(s).
+
+The stop bits are specified as 0.5, 1, 1.5 or 2.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] stopbits unsigned 32 bit. Stop bits @ref usart_cr2_stopbits.
+*/
+
+void usart_set_stopbits(uint32_t usart, uint32_t stopbits)
+{
+ uint32_t reg32;
+
+ reg32 = USART_CR2(usart);
+ reg32 = (reg32 & ~USART_CR2_STOPBITS_MASK) | stopbits;
+ USART_CR2(usart) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Parity.
+
+The parity bit can be selected as none, even or odd.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] parity unsigned 32 bit. Parity @ref usart_cr1_parity.
+*/
+
+void usart_set_parity(uint32_t usart, uint32_t parity)
+{
+ uint32_t reg32;
+
+ reg32 = USART_CR1(usart);
+ reg32 = (reg32 & ~USART_PARITY_MASK) | parity;
+ USART_CR1(usart) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Rx/Tx Mode.
+
+The mode can be selected as Rx only, Tx only or Rx+Tx.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] mode unsigned 32 bit. Mode @ref usart_cr1_mode.
+*/
+
+void usart_set_mode(uint32_t usart, uint32_t mode)
+{
+ uint32_t reg32;
+
+ reg32 = USART_CR1(usart);
+ reg32 = (reg32 & ~USART_MODE_MASK) | mode;
+ USART_CR1(usart) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Set Hardware Flow Control.
+
+The flow control bit can be selected as none, RTS, CTS or RTS+CTS.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] flowcontrol unsigned 32 bit. Flowcontrol @ref usart_cr3_flowcontrol.
+*/
+
+void usart_set_flow_control(uint32_t usart, uint32_t flowcontrol)
+{
+ uint32_t reg32;
+
+ reg32 = USART_CR3(usart);
+ reg32 = (reg32 & ~USART_FLOWCONTROL_MASK) | flowcontrol;
+ USART_CR3(usart) = reg32;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Enable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_enable(uint32_t usart)
+{
+ USART_CR1(usart) |= USART_CR1_UE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Disable.
+
+At the end of the current frame, the USART is disabled to reduce power.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_disable(uint32_t usart)
+{
+ USART_CR1(usart) &= ~USART_CR1_UE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Send Data Word with Blocking
+
+Blocks until the transmit data buffer becomes empty then writes the next data
+word for transmission.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] data unsigned 16 bit.
+*/
+
+void usart_send_blocking(uint32_t usart, uint16_t data)
+{
+ usart_wait_send_ready(usart);
+ usart_send(usart, data);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Read a Received Data Word with Blocking.
+
+Wait until a data word has been received then return the word.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@returns unsigned 16 bit data word.
+*/
+
+uint16_t usart_recv_blocking(uint32_t usart)
+{
+ usart_wait_recv_ready(usart);
+
+ return usart_recv(usart);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Receiver DMA Enable.
+
+DMA is available on:
+@li USART1 Rx DMA1 channel 5.
+@li USART2 Rx DMA1 channel 6.
+@li USART3 Rx DMA1 channel 3.
+@li UART4 Rx DMA2 channel 3.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_enable_rx_dma(uint32_t usart)
+{
+ USART_CR3(usart) |= USART_CR3_DMAR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Receiver DMA Disable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_disable_rx_dma(uint32_t usart)
+{
+ USART_CR3(usart) &= ~USART_CR3_DMAR;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Transmitter DMA Enable.
+
+DMA is available on:
+@li USART1 Tx DMA1 channel 4.
+@li USART2 Tx DMA1 channel 7.
+@li USART3 Tx DMA1 channel 2.
+@li UART4 Tx DMA2 channel 5.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_enable_tx_dma(uint32_t usart)
+{
+ USART_CR3(usart) |= USART_CR3_DMAT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Transmitter DMA Disable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_disable_tx_dma(uint32_t usart)
+{
+ USART_CR3(usart) &= ~USART_CR3_DMAT;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Receiver Interrupt Enable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_enable_rx_interrupt(uint32_t usart)
+{
+ USART_CR1(usart) |= USART_CR1_RXNEIE;
+}
+
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Receiver Interrupt Disable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_disable_rx_interrupt(uint32_t usart)
+{
+ USART_CR1(usart) &= ~USART_CR1_RXNEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Transmitter Interrupt Enable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_enable_tx_interrupt(uint32_t usart)
+{
+ USART_CR1(usart) |= USART_CR1_TXEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Transmitter Interrupt Disable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_disable_tx_interrupt(uint32_t usart)
+{
+ USART_CR1(usart) &= ~USART_CR1_TXEIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Error Interrupt Enable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_enable_error_interrupt(uint32_t usart)
+{
+ USART_CR3(usart) |= USART_CR3_EIE;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Error Interrupt Disable.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_disable_error_interrupt(uint32_t usart)
+{
+ USART_CR3(usart) &= ~USART_CR3_EIE;
+}
+
+/**@}*/
+
diff --git a/libopencm3/lib/stm32/common/usart_common_f124.c b/libopencm3/lib/stm32/common/usart_common_f124.c
new file mode 100644
index 0000000..ea5b4ee
--- /dev/null
+++ b/libopencm3/lib/stm32/common/usart_common_f124.c
@@ -0,0 +1,143 @@
+/** @addtogroup usart_file
+
+@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
+
+This library supports the USART/UART in the STM32F series
+of ARM Cortex Microcontrollers by ST Microelectronics.
+
+Devices can have up to 3 USARTs and 2 UARTs.
+
+*/
+
+/*
+ * 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/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/usart.h>
+#include <libopencm3/stm32/rcc.h>
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Send a Data Word.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] data unsigned 16 bit.
+*/
+
+void usart_send(uint32_t usart, uint16_t data)
+{
+ /* Send data. */
+ USART_DR(usart) = (data & USART_DR_MASK);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Read a Received Data Word.
+
+If parity is enabled the MSB (bit 7 or 8 depending on the word length) is the
+parity bit.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@returns unsigned 16 bit data word.
+*/
+
+uint16_t usart_recv(uint32_t usart)
+{
+ /* Receive data. */
+ return USART_DR(usart) & USART_DR_MASK;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Wait for Transmit Data Buffer Empty
+
+Blocks until the transmit data buffer becomes empty and is ready to accept the
+next data word.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_wait_send_ready(uint32_t usart)
+{
+ /* Wait until the data has been transferred into the shift register. */
+ while ((USART_SR(usart) & USART_SR_TXE) == 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Wait for Received Data Available
+
+Blocks until the receive data buffer holds a valid received data word.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+*/
+
+void usart_wait_recv_ready(uint32_t usart)
+{
+ /* Wait until the data is ready to be received. */
+ while ((USART_SR(usart) & USART_SR_RXNE) == 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Read a Status Flag.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags.
+@returns boolean: flag set.
+*/
+
+bool usart_get_flag(uint32_t usart, uint32_t flag)
+{
+ return ((USART_SR(usart) & flag) != 0);
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief USART Return Interrupt Source.
+
+Returns true if the specified interrupt flag (IDLE, RXNE, TC, TXE or OE) was
+set and the interrupt was enabled. If the specified flag is not an interrupt
+flag, the function returns false.
+
+@todo These are the most important interrupts likely to be used. Others
+relating to LIN break, and error conditions in multibuffer communication, need
+to be added for completeness.
+
+@param[in] usart unsigned 32 bit. USART block register address base @ref
+usart_reg_base
+@param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags.
+@returns boolean: flag and interrupt enable both set.
+*/
+
+bool usart_get_interrupt_source(uint32_t usart, uint32_t flag)
+{
+ uint32_t flag_set = (USART_SR(usart) & flag);
+ /* IDLE, RXNE, TC, TXE interrupts */
+ if ((flag >= USART_SR_IDLE) && (flag <= USART_SR_TXE)) {
+ return ((flag_set & USART_CR1(usart)) != 0);
+ /* Overrun error */
+ } else if (flag == USART_SR_ORE) {
+ return flag_set && (USART_CR3(usart) & USART_CR3_CTSIE);
+ }
+
+ return false;
+}
+
+/**@}*/