aboutsummaryrefslogtreecommitdiff
path: root/lib/stm32
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stm32')
-rw-r--r--lib/stm32/crc.c44
-rw-r--r--lib/stm32/dac.c520
-rw-r--r--lib/stm32/f1/Makefile26
-rw-r--r--lib/stm32/f1/adc.c514
-rw-r--r--lib/stm32/f1/desig.c37
-rw-r--r--lib/stm32/f1/dma.c229
-rw-r--r--lib/stm32/f1/gpio.c232
-rw-r--r--lib/stm32/f1/libopencm3_stm32f1.ld19
-rw-r--r--lib/stm32/f1/pwr.c217
-rw-r--r--lib/stm32/f1/rcc.c372
-rw-r--r--lib/stm32/f1/stm32f100x4.ld31
-rw-r--r--lib/stm32/f1/stm32f100x6.ld31
-rw-r--r--lib/stm32/f1/stm32f100x8.ld31
-rw-r--r--lib/stm32/f1/stm32f100xb.ld31
-rw-r--r--lib/stm32/f1/stm32f100xc.ld31
-rw-r--r--lib/stm32/f1/stm32f100xd.ld31
-rw-r--r--lib/stm32/f1/stm32f100xe.ld31
-rw-r--r--lib/stm32/f1/timer.c986
-rw-r--r--lib/stm32/f1/vector.c6
-rw-r--r--lib/stm32/f2/Makefile25
-rw-r--r--lib/stm32/f2/gpio.c5
-rw-r--r--lib/stm32/f2/libopencm3_stm32f2.ld19
-rw-r--r--lib/stm32/f2/vector.c4
-rw-r--r--lib/stm32/f4/Makefile25
-rw-r--r--lib/stm32/f4/gpio.c5
-rw-r--r--lib/stm32/f4/libopencm3_stm32f4.ld30
-rw-r--r--lib/stm32/f4/vector.c4
-rw-r--r--lib/stm32/iwdg.c144
-rw-r--r--lib/stm32/nvic.c111
-rw-r--r--lib/stm32/systick.c75
30 files changed, 3655 insertions, 211 deletions
diff --git a/lib/stm32/crc.c b/lib/stm32/crc.c
new file mode 100644
index 0000000..bbbe1fd
--- /dev/null
+++ b/lib/stm32/crc.c
@@ -0,0 +1,44 @@
+/*
+ * 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>
+
+void crc_reset(void)
+{
+ CRC_CR |= CRC_CR_RESET;
+}
+
+u32 crc_calculate(u32 data)
+{
+ CRC_DR = data;
+ // Data sheet says this blocks until it's ready....
+ return CRC_DR;
+}
+
+u32 crc_calculate_block(u32 *datap, int size)
+{
+ int i;
+ for (i = 0; i < size; i++) {
+ CRC_DR = datap[i];
+ }
+ return CRC_DR;
+}
+
+
+
diff --git a/lib/stm32/dac.c b/lib/stm32/dac.c
new file mode 100644
index 0000000..55440bf
--- /dev/null
+++ b/lib/stm32/dac.c
@@ -0,0 +1,520 @@
+/** @defgroup STM32F_dac_file DAC
+
+@ingroup STM32F_files
+
+@brief <b>libopencm3 STM32Fxx Digital to Analog Converter</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies
+
+@date 18 August 2012
+
+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 the GPIO
+ports set to alternate function output before it can be used.
+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 any alternate function output mode. 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,(u32) &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 u32. 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(u32 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 u32. 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(u32 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 u32. 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(u32 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
+
+This function can also be used to load the dual channel registers if the data is
+formatted according to the datasheets:
+@li right-aligned 8 bit data in bits 0-7 for channel 1 and 8-15 for channel 2
+@li right-aligned 12 bit data in bits 0-11 for channel 1 and 16-27 for channel 2
+@li left aligned 12 bit data in bits 4-15 for channel 1 and 20-31 for channel 2
+
+@param[in] dac_data u32 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(u32 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;
+ }
+ }
+ else
+ switch (dac_data_format) {
+ case RIGHT8:
+ DAC_DHR8RD = dac_data;
+ break;
+ case RIGHT12:
+ DAC_DHR12RD = dac_data;
+ break;
+ case LEFT12:
+ DAC_DHR12LD = 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 u32 for channel 1 with appropriate alignment.
+@param[in] dac_data2 u32 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(u32 dac_data1, u32 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) << 12));
+ 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/lib/stm32/f1/Makefile b/lib/stm32/f1/Makefile
index d598f84..3b4252b 100644
--- a/lib/stm32/f1/Makefile
+++ b/lib/stm32/f1/Makefile
@@ -31,31 +31,9 @@ ARFLAGS = rcs
OBJS = vector.o rcc.o gpio.o usart.o adc.o spi.o flash.o nvic.o \
rtc.o i2c.o dma.o systick.o exti.o scb.o ethernet.o \
usb_f103.o usb.o usb_control.o usb_standard.o can.o \
- timer.o usb_f107.o
+ timer.o usb_f107.o desig.o crc.o
VPATH += ../../usb:../
-# Be silent per default, but 'make V=1' will show all compiler calls.
-ifneq ($(V),1)
-Q := @
-endif
-
-all: $(LIBNAME).a
-
-$(LIBNAME).a: $(OBJS)
- @printf " AR $(subst $(shell pwd)/,,$(@))\n"
- $(Q)$(AR) $(ARFLAGS) $@ $^
-
-%.o: %.c
- @printf " CC $(subst $(shell pwd)/,,$(@))\n"
- $(Q)$(CC) $(CFLAGS) -o $@ -c $<
-
-clean:
- @printf " CLEAN lib/stm32/f1\n"
- $(Q)rm -f *.o *.d
- $(Q)rm -f $(LIBNAME).a
-
-.PHONY: clean
-
--include $(OBJS:.o=.d)
+include ../../Makefile.include
diff --git a/lib/stm32/f1/adc.c b/lib/stm32/f1/adc.c
index f07164f..433cdd2 100644
--- a/lib/stm32/f1/adc.c
+++ b/lib/stm32/f1/adc.c
@@ -1,3 +1,70 @@
+/** @defgroup STM32F1xx_adc_file ADC
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx Analog to Digital Converters</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2009 Edward Cheeseman <evbuilder@users.sourceforge.net>
+@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies <ksarkies@internode.on.net>
+
+@date 18 August 2012
+
+This library supports the A/D Converter Control System in the STM32F1xx series
+of ARM Cortex Microcontrollers by ST Microelectronics.
+
+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 which is prescaled from the APB2
+clock by default by a minimum factor of 2 to a maximum of 8.
+
+Each A/D converter has up to 18 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 the analog channels 16 and 17 are internally connected to V<sub>SS</sub>.
+@li On ADC3 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.
+
+@code
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_ADC1EN);
+ adc_power_on(ADC1);
+ adc_calibration(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_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.
*
@@ -27,10 +94,12 @@
* rcc_peripheral_clear_reset(&RCC_APB2RSTR, ADC1RST);
*
* rcc_set_adc_clk(ADC_PRE_PLCK2_DIV2);
- * adc_set_mode(ADC1, TODO);
+ * adc_set_dual_mode(ADC1, TODO);
* reg16 = adc_read(ADC1, ADC_CH_0);
*/
+/**@{*/
+
#include <libopencm3/stm32/f1/adc.h>
void rcc_set_adc_clk(u32 prescaler)
@@ -50,6 +119,14 @@ void adc_set_mode(u32 block, /* TODO */ u8 mode)
mode = mode;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief ADC Read from a Conversion Result Register
+
+@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.
+*/
+
void adc_read(u32 block, u32 channel)
{
/* TODO */
@@ -59,61 +136,177 @@ void adc_read(u32 block, u32 channel)
channel = channel;
}
+/*-----------------------------------------------------------------------------*/
+/** @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(u32 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(u32 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(u32 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(u32 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_discontinous_mode_regular(u32 adc)
{
ADC_CR1(adc) |= ADC_CR1_DISCEN;
}
+/*-----------------------------------------------------------------------------*/
+/** @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_discontinous_mode_regular(u32 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_discontinous_mode_injected(u32 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_discontinous_mode_injected(u32 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(u32 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(u32 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(u32 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(u32 adc, u8 channel)
{
u32 reg32;
@@ -125,56 +318,140 @@ void adc_enable_analog_watchdog_on_selected_channel(u32 adc, u8 channel)
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(u32 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(u32 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_jeoc_interrupt(u32 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_jeoc_interrupt(u32 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(u32 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(u32 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(u32 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(u32 adc)
{
ADC_CR1(adc) &= ~ADC_CR1_EOCIE;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief ADC Enable The Temperature Sensor
+
+This enables both the sensor and the reference voltage measurements on channels
+16 and 17.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
void adc_enable_temperature_sensor(u32 adc)
{
ADC_CR2(adc) |= ADC_CR2_TSVREFE;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief ADC Disable The Temperature Sensor
+
+Disabling this will reduce power consumption from the sensor and the reference
+voltage measurements.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
void adc_disable_temperature_sensor(u32 adc)
{
ADC_CR2(adc) &= ~ADC_CR2_TSVREFE;
}
+/*-----------------------------------------------------------------------------*/
+/** @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.
+
+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(u32 adc)
{
/* Start conversion on regular channels. */
@@ -184,6 +461,20 @@ void adc_start_conversion_regular(u32 adc)
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.
+
+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(u32 adc)
{
/* Start conversion on injected channels. */
@@ -193,6 +484,36 @@ void adc_start_conversion_injected(u32 adc)
while (ADC_CR2(adc) & ADC_CR2_JSWSTART);
}
+/*-----------------------------------------------------------------------------*/
+/** @brief ADC Enable an External Trigger for Regular Channels
+
+This enables an external trigger for set of defined regular channels.
+
+For ADC1 and ADC2
+@li Timer 1 CC1 event
+@li Timer 1 CC2 event
+@li Timer 1 CC3 event
+@li Timer 2 CC2 event
+@li Timer 3 TRGO event
+@li Timer 4 CC4 event
+@li EXTI (TIM8_TRGO is also possible on some devices, see datasheet)
+@li Software Start
+
+For ADC3
+@li Timer 3 CC1 event
+@li Timer 2 CC3 event
+@li Timer 1 CC3 event
+@li Timer 8 CC1 event
+@li Timer 8 TRGO event
+@li Timer 5 CC1 event
+@li Timer 5 CC3 event
+@li Software Start
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] trigger Unsigned int8. Trigger identifier @ref adc_trigger_regular_12
+for ADC1 and ADC2, or @ref adc_trigger_regular_3 for ADC3
+*/
+
void adc_enable_external_trigger_regular(u32 adc, u32 trigger)
{
u32 reg32;
@@ -204,11 +525,47 @@ void adc_enable_external_trigger_regular(u32 adc, u32 trigger)
ADC_CR2(adc) |= ADC_CR2_EXTTRIG;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief ADC Disable an External Trigger for Regular Channels
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
void adc_disable_external_trigger_regular(u32 adc)
{
ADC_CR2(adc) &= ~ADC_CR2_EXTTRIG;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief ADC Enable an External Trigger for Injected Channels
+
+This enables an external trigger for set of defined injected channels.
+
+For ADC1 and ADC2
+@li Timer 1 TRGO event
+@li Timer 1 CC4 event
+@li Timer 2 TRGO event
+@li Timer 2 CC1 event
+@li Timer 3 CC4 event
+@li Timer 4 TRGO event
+@li EXTI (TIM8 CC4 is also possible on some devices, see datasheet)
+@li Software Start
+
+For ADC3
+@li Timer 1 TRGO event
+@li Timer 1 CC4 event
+@li Timer 4 CC3 event
+@li Timer 8 CC2 event
+@li Timer 8 CC4 event
+@li Timer 5 TRGO event
+@li Timer 5 CC4 event
+@li Software Start
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] trigger Unsigned int8. Trigger identifier @ref adc_trigger_injected_12
+for ADC1 and ADC2, or @ref adc_trigger_injected_3 for ADC3
+*/
+
void adc_enable_external_trigger_injected(u32 adc, u32 trigger)
{
u32 reg32;
@@ -220,65 +577,169 @@ void adc_enable_external_trigger_injected(u32 adc, u32 trigger)
ADC_CR2(adc) |= ADC_CR2_JEXTTRIG;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief ADC Disable an External Trigger for Injected Channels
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
void adc_disable_external_trigger_injected(u32 adc)
{
ADC_CR2(adc) &= ~ADC_CR2_JEXTTRIG;
}
+/*-----------------------------------------------------------------------------*/
+/** @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(u32 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(u32 adc)
{
ADC_CR2(adc) &= ~ADC_CR2_ALIGN;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief ADC Enable DMA Transfers
+
+Only available for ADC1 through DMA1 channel1, and ADC3 through DMA2 channel5.
+ADC2 will use DMA if it is set as slave in dual mode with ADC1 in DMA transfer
+mode.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
void adc_enable_dma(u32 adc)
{
if ((adc == ADC1) | (adc == ADC3))
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(u32 adc)
{
if ((adc == ADC1) | (adc == ADC3))
ADC_CR2(adc) &= ~ADC_CR2_DMA;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief ADC Initialize Calibration Registers
+
+This resets the calibration registers. It is not clear if this is required to be
+done before every calibration operation.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
void adc_reset_calibration(u32 adc)
{
ADC_CR2(adc) |= ADC_CR2_RSTCAL;
while (ADC_CR2(adc) & ADC_CR2_RSTCAL);
}
+/*-----------------------------------------------------------------------------*/
+/** @brief ADC Calibration
+
+The calibration data for the ADC is recomputed. The hardware clears the
+calibration status flag when calibration is complete. This function does not return
+until this happens and the ADC is ready for use.
+
+The ADC must have been powered down for at least 2 ADC clock cycles, then powered on.
+before calibration starts
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
void adc_calibration(u32 adc)
{
ADC_CR2(adc) |= ADC_CR2_CAL;
while (ADC_CR2(adc) & ADC_CR2_CAL);
}
+/*-----------------------------------------------------------------------------*/
+/** @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_continous_conversion_mode(u32 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(u32 adc)
{
ADC_CR2(adc) &= ~ADC_CR2_CONT;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief ADC Power On
+
+If the ADC is in power-down mode then it is powered up. The application needs
+to wait a time of about 3 microseconds for stabilization before using the ADC.
+If the ADC is already on this function call will initiate a conversion.
+
+@todo fix this.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+*/
+
void adc_on(u32 adc)
{
ADC_CR2(adc) |= ADC_CR2_ADON;
}
+/*-----------------------------------------------------------------------------*/
+/** @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(u32 adc)
{
ADC_CR2(adc) &= ~ADC_CR2_ADON;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief ADC Set the Sample Time for a Single Channel
+
+The sampling time can be selected in ADC clock cycles from 1.5 to 239.5.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] channel Unsigned int8. ADC Channel integer 0..18 or from @ref adc_channel
+@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg
+*/
+
void adc_set_conversion_time(u32 adc, u8 channel, u8 time)
{
u32 reg32;
@@ -296,6 +757,16 @@ void adc_set_conversion_time(u32 adc, u8 channel, u8 time)
}
}
+/*-----------------------------------------------------------------------------*/
+/** @brief ADC Set the Sample Time for All Channels
+
+The sampling time can be selected in ADC clock cycles from 1.5 to 239.5, same for
+all channels.
+
+@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
+@param[in] time Unsigned int8. Sampling time selection from @ref adc_sample_rg
+*/
+
void adc_set_conversion_time_on_all_channels(u32 adc, u8 time)
{
u8 i;
@@ -310,6 +781,13 @@ void adc_set_conversion_time_on_all_channels(u32 adc, u8 time)
ADC_SMPR1(adc) = reg32;
}
+/*-----------------------------------------------------------------------------*/
+/** @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(u32 adc, u16 threshold)
{
u32 reg32 = 0;
@@ -319,6 +797,13 @@ void adc_set_watchdog_high_threshold(u32 adc, u16 threshold)
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(u32 adc, u16 threshold)
{
u32 reg32 = 0;
@@ -328,6 +813,18 @@ void adc_set_watchdog_low_threshold(u32 adc, u16 threshold)
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 16 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_regular_sequence(u32 adc, u8 length, u8 channel[])
{
u32 reg32_1 = 0, reg32_2 = 0, reg32_3 = 0;
@@ -352,6 +849,18 @@ void adc_set_regular_sequence(u32 adc, u8 length, u8 channel[])
ADC_SQR3(adc) = reg32_3;
}
+/*-----------------------------------------------------------------------------*/
+/** @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(u32 adc, u8 length, u8 channel[])
{
u32 reg32 = 0;
@@ -368,3 +877,6 @@ void adc_set_injected_sequence(u32 adc, u8 length, u8 channel[])
ADC_JSQR(adc) = reg32;
}
+
+/**@}*/
+
diff --git a/lib/stm32/f1/desig.c b/lib/stm32/f1/desig.c
new file mode 100644
index 0000000..7ae968e
--- /dev/null
+++ b/lib/stm32/f1/desig.c
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2012 Karl Palsson <karlp@ŧweak.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/f1/desig.h>
+
+u16 desig_get_flash_size(void)
+{
+ return DESIG_FLASH_SIZE;
+}
+
+void desig_get_unique_id(u32 result[])
+{
+ // Could also just return a pointer to the start? read it as they wish?
+ u16 bits15_0 = DESIG_UID_15_0;
+ u32 bits31_16 = DESIG_UID_31_16;
+ u32 bits63_32 = DESIG_UID_63_32;
+ u32 bits95_64 = DESIG_UID_95_64;
+ result[0] = bits95_64;
+ result[1] = bits63_32;
+ result[2] = bits31_16 << 16 | bits15_0;
+}
diff --git a/lib/stm32/f1/dma.c b/lib/stm32/f1/dma.c
index 6bcb396..04cb8a1 100644
--- a/lib/stm32/f1/dma.c
+++ b/lib/stm32/f1/dma.c
@@ -1,3 +1,24 @@
+/** @defgroup STM32F1xx-dma-file DMA
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx DMA Controller</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
+
+@date 18 August 2012
+
+This library supports the DMA
+Control System in the STM32F1xx series of ARM Cortex Microcontrollers
+by ST Microelectronics. It can provide for two DMA controllers,
+one with 7 channels and one with 5. Channels are hardware dedicated
+and each is shared with a number of different sources (only one can be
+used at a time, under the responsibility of the programmer).
+
+LGPL License Terms @ref lgpl_license
+ */
/*
* This file is part of the libopencm3 project.
*
@@ -17,8 +38,19 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
+/**@{*/
+
#include <libopencm3/stm32/f1/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(u32 dma, u8 channel)
{
/* Disable channel. */
@@ -35,18 +67,51 @@ void dma_channel_reset(u32 dma, u8 channel)
DMA_IFCR(dma) |= DMA_IFCR_CIF(channel);
}
+/*-----------------------------------------------------------------------------*/
+/** @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(u32 dma, u8 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(u32 dma, u8 channel, u32 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(u32 dma, u8 channel, u32 mem_size)
{
@@ -54,89 +119,249 @@ void dma_set_memory_size(u32 dma, u8 channel, u32 mem_size)
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(u32 dma, u8 channel, u32 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(u32 dma, u8 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_enable_peripheral_increment_mode(u32 dma, u8 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(u32 dma, u8 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(u32 dma, u8 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(u32 dma, u8 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(u32 dma, u8 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(u32 dma, u8 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(u32 dma, u8 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(u32 dma, u8 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(u32 dma, u8 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(u32 dma, u8 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(u32 dma, u8 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(u32 dma, u8 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(u32 dma, u8 channel, u32 address)
{
- DMA_CPAR(dma, channel) = (u32) address;
+ if (!(DMA_CCR(dma, channel) & DMA_CCR_EN))
+ DMA_CPAR(dma, channel) = (u32) 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(u32 dma, u8 channel, u32 address)
{
- DMA_CMAR(dma, channel) = (u32) address;
+ if (!(DMA_CCR(dma, channel) & DMA_CCR_EN))
+ DMA_CMAR(dma, channel) = (u32) 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(u32 dma, u8 channel, u16 number)
{
DMA_CNDTR(dma, channel) = number;
}
+/**@}*/
+
diff --git a/lib/stm32/f1/gpio.c b/lib/stm32/f1/gpio.c
index 4f7e663..0602012 100644
--- a/lib/stm32/f1/gpio.c
+++ b/lib/stm32/f1/gpio.c
@@ -1,3 +1,61 @@
+/** @defgroup STM32F1xx_gpio_file GPIO
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx General Purpose I/O</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
+@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies <ksarkies@internode.on.net>
+
+@date 18 August 2012
+
+This library supports the General Purpose I/O System in the STM32F1xx series
+of ARM Cortex Microcontrollers by ST Microelectronics.
+
+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 on ports C2 and C9
+
+@code
+ gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO2 | GPIO9);
+ gpio_set(GPIOC, GPIO2 | GPIO9);
+ gpio_clear(GPIOC, GPIO2);
+ gpio_toggle(GPIOC, GPIO2 | GPIO9);
+ gpio_port_write(GPIOC, 0x204);
+@endcode
+
+Example 1: Digital input on port C12
+
+@code
+ gpio_set_mode(GPIOC, GPIO_MODE_INPUT, GPIO_CNF_INPUT, GPIO12);
+ reg16 = gpio_port_read(GPIOC);
+@endcode
+
+LGPL License Terms @ref lgpl_license
+ */
/*
* This file is part of the libopencm3 project.
*
@@ -33,9 +91,23 @@
* TODO:
* - GPIO remapping support
*/
+/**@{*/
#include <libopencm3/stm32/f1/gpio.h>
+/*-----------------------------------------------------------------------------*/
+/** @brief Set GPIO Pin Mode
+
+Sets the mode (input/output) and configuration (analog/digitial and
+open drain/push pull), 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] cnf Unsigned int8. Pin configuration @ref gpio_cnf
+@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
+ If multiple pins are to be set, use logical OR '|' to separate them.
+*/
+
void gpio_set_mode(u32 gpioport, u8 mode, u8 cnf, u16 gpios)
{
u16 i, offset = 0;
@@ -73,69 +145,99 @@ void gpio_set_mode(u32 gpioport, u8 mode, u8 cnf, u16 gpios)
GPIO_CRH(gpioport) = crh;
}
-/**
- * Set one or more pins of the given GPIO port to 1.
- *
- * @param gpioport The GPIO port to use (GPIOA - GPIOG).
- * @param gpios The GPIO pin(s) to set to 1 (GPIO0 - GPIO15, or GPIO_ALL).
- * If multiple pins shall be set, use '|' to separate them.
- */
+/*-----------------------------------------------------------------------------*/
+/** @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(u32 gpioport, u16 gpios)
{
GPIO_BSRR(gpioport) = gpios;
}
-/**
- * Clear one or more pins of the given GPIO port to 0.
- *
- * @param gpioport The GPIO port to use (GPIOA - GPIOG).
- * @param gpios The GPIO pin(s) to set to 0 (GPIO0 - GPIO15, or GPIO_ALL).
- * If multiple pins shall be cleared, use '|' to separate them.
- */
+/*-----------------------------------------------------------------------------*/
+/** @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(u32 gpioport, u16 gpios)
{
GPIO_BRR(gpioport) = gpios;
}
+/*-----------------------------------------------------------------------------*/
+/** @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.
+*/
u16 gpio_get(u32 gpioport, u16 gpios)
{
return gpio_port_read(gpioport) & gpios;
}
-/**
- * Toggle one or more pins of the given GPIO port.
- *
- * @param gpioport The GPIO port to use (GPIOA - GPIOG).
- * @param gpios The GPIO pin(s) to toggle (GPIO0 - GPIO15, or GPIO_ALL).
- * If multiple pins shall be toggled, use '|' to separate them.
- */
+/*-----------------------------------------------------------------------------*/
+/** @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(u32 gpioport, u16 gpios)
{
GPIO_ODR(gpioport) ^= gpios;
}
-/**
- * Read the current value of the given GPIO port.
- *
- * @param gpioport The GPIO port to read (GPIOA - GPIOG).
- * @return The value of the current GPIO port.
- */
+/*-----------------------------------------------------------------------------*/
+/** @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.
+*/
u16 gpio_port_read(u32 gpioport)
{
return (u16)GPIO_IDR(gpioport);
}
-/**
- * Write to the given GPIO port.
- *
- * @param gpioport The GPIO port to write to (GPIOA - GPIOG).
- * @param data The data to write to the specified GPIO port.
- */
+/*-----------------------------------------------------------------------------*/
+/** @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(u32 gpioport, u16 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(u32 gpioport, u16 gpios)
{
u32 reg32;
@@ -147,5 +249,69 @@ void gpio_port_config_lock(u32 gpioport, u16 gpios)
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. */
}
+
+/*-----------------------------------------------------------------------------*/
+/** @brief Map the EVENTOUT signal
+
+Enable the EVENTOUT signal and select the port and pin to be used.
+
+@param[in] evoutport Unsigned int8. Port for EVENTOUT signal @ref afio_evcr_port
+@param[in] evoutpin Unsigned int8. Pin for EVENTOUT signal @ref afio_evcr_pin
+*/
+void gpio_set_eventout(u8 evoutport, u8 evoutpin)
+{
+ AFIO_EVCR = AFIO_EVCR_EVOE | evoutport | evoutpin;
+}
+
+/*-----------------------------------------------------------------------------*/
+/** @brief Map Alternate Function Port Bits (Main Set)
+
+A number of alternate function ports can be remapped to defined alternative
+port bits to avoid clashes in cases where multiple alternate functions are present.
+Refer to the datasheets for the particular mapping desired. This provides the main
+set of remap functionality. See @ref gpio_secondary_remap for a number of lesser used
+remaps.
+
+The AFIO remapping feature is used only with the STM32F10x series.
+
+@note The Serial Wire JTAG disable controls allow certain GPIO ports to become available
+in place of some of the SWJ signals. Full SWJ capability is obtained by setting this to
+zero. The value of this must be specified for every call to this function as its current
+value cannot be ascertained from the hardware.
+
+@param[in] swjdisable Unsigned int8. Disable parts of the SWJ capability @ref afio_swj_disable.
+@param[in] maps Unsigned int32. Logical OR of map enable controls from @ref afio_remap,
+ @ref afio_remap_can1, @ref afio_remap_tim3, @ref afio_remap_tim2, @ref afio_remap_tim1,
+ @ref afio_remap_usart3. For connectivity line devices only @ref afio_remap_cld are
+ also available.
+*/
+void gpio_primary_remap(u8 swjdisable, u32 maps)
+{
+ AFIO_MAPR = swjdisable | (maps & 0x1FFFFF);
+}
+
+/*-----------------------------------------------------------------------------*/
+/** @brief Map Alternate Function Port Bits (Secondary Set)
+
+A number of alternate function ports can be remapped to defined alternative
+port bits to avoid clashes in cases where multiple alternate functions are present.
+Refer to the datasheets for the particular mapping desired. This provides the second
+smaller and less used set of remap functionality. See @ref gpio_primary_remap for
+the main set of remaps.
+
+The AFIO remapping feature is used only with the STM32F10x series.
+
+@param[in] maps Unsigned int32. Logical OR of map enable controls from @ref afio_remap2
+*/
+void gpio_secondary_remap(u32 maps)
+{
+ AFIO_MAPR2 = maps;
+}
+
+/**@}*/
+
diff --git a/lib/stm32/f1/libopencm3_stm32f1.ld b/lib/stm32/f1/libopencm3_stm32f1.ld
index a64a1f7..9d165f6 100644
--- a/lib/stm32/f1/libopencm3_stm32f1.ld
+++ b/lib/stm32/f1/libopencm3_stm32f1.ld
@@ -30,21 +30,18 @@ ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
- . = ORIGIN(rom);
-
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
- _etext = .;
} >rom
/*
- * Another section used by C++ stuff, appears when using newlib with
- * 64bit (long long) printf support
- */
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
.ARM.extab : {
*(.ARM.extab*)
} >rom
@@ -54,21 +51,23 @@ SECTIONS
__exidx_end = .;
} >rom
- . = ORIGIN(ram);
+ . = ALIGN(4);
+ _etext = .;
- .data : AT (__exidx_end) {
+ .data : {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
- } >ram
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
- } >ram AT >rom
+ } >ram
/*
* The .eh_frame section appears to be used for C++ exception handling.
diff --git a/lib/stm32/f1/pwr.c b/lib/stm32/f1/pwr.c
new file mode 100644
index 0000000..83c3dba
--- /dev/null
+++ b/lib/stm32/f1/pwr.c
@@ -0,0 +1,217 @@
+/** @defgroup STM32F1xx-pwr-file PWR
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx Power Control</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies <ksarkies@internode.on.net>
+
+@date 18 August 2012
+
+This library supports the power control system for the
+STM32F1 series of ARM Cortex Microcontrollers by ST Microelectronics.
+
+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/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 u32. Taken from @ref pwr_pls.
+*/
+
+void pwr_enable_power_voltage_detect(u32 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_CR_EWUP;
+}
+
+/*---------------------------------------------------------------------------*/
+/** @brief Release Wakeup Pin.
+
+The wakeup pin is used for general purpose I/O.
+*/
+
+void pwr_disable_wakeup_pin(void)
+{
+ PWR_CSR &= ~PWR_CR_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_CR_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_CR_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_CR_WUF);
+}
+/**@}*/
+
diff --git a/lib/stm32/f1/rcc.c b/lib/stm32/f1/rcc.c
index 8945e80..5fd9c62 100644
--- a/lib/stm32/f1/rcc.c
+++ b/lib/stm32/f1/rcc.c
@@ -1,3 +1,30 @@
+/** @defgroup STM32F1xx-rcc-file RCC
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx Reset and Clock Control</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2009 Federico Ruiz-Ugalde \<memeruiz at gmail dot com\>
+@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
+@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
+
+@date 18 August 2012
+
+This library supports the Reset and Clock Control System in the STM32F1xx
+series of ARM Cortex Microcontrollers by ST Microelectronics.
+
+@note Full support for connection line devices is not yet provided.
+
+Clock settings and resets for many peripherals are given here rather than in the
+corresponding peripheral library.
+
+The library also provides a number of common configurations for the processor
+system clock. Not all possible configurations are included.
+
+LGPL License Terms @ref lgpl_license
+ */
/*
* This file is part of the libopencm3 project.
*
@@ -19,13 +46,24 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
+/**@{*/
+
#include <libopencm3/stm32/f1/rcc.h>
#include <libopencm3/stm32/f1/flash.h>
-/* Set the default ppre1 and ppre2 peripheral clock frequencies after reset. */
+/** Default ppre1 peripheral clock frequency after reset. */
u32 rcc_ppre1_frequency = 8000000;
+/** Default ppre2 peripheral clock frequency after reset. */
u32 rcc_ppre2_frequency = 8000000;
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Clear the Oscillator Ready Interrupt Flag
+
+Clear the interrupt flag that was set when a clock oscillator became ready to use.
+
+@param[in] osc enum ::osc_t. Oscillator ID
+*/
+
void rcc_osc_ready_int_clear(osc_t osc)
{
switch (osc) {
@@ -47,6 +85,12 @@ void rcc_osc_ready_int_clear(osc_t osc)
}
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Enable the Oscillator Ready Interrupt
+
+@param[in] osc enum ::osc_t. Oscillator ID
+*/
+
void rcc_osc_ready_int_enable(osc_t osc)
{
switch (osc) {
@@ -68,6 +112,12 @@ void rcc_osc_ready_int_enable(osc_t osc)
}
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Disable the Oscillator Ready Interrupt
+
+@param[in] osc enum ::osc_t. Oscillator ID
+*/
+
void rcc_osc_ready_int_disable(osc_t osc)
{
switch (osc) {
@@ -89,6 +139,13 @@ void rcc_osc_ready_int_disable(osc_t osc)
}
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Read the Oscillator Ready Interrupt Flag
+
+@param[in] osc enum ::osc_t. Oscillator ID
+@returns int. Boolean value for flag set.
+*/
+
int rcc_osc_ready_int_flag(osc_t osc)
{
switch (osc) {
@@ -113,16 +170,33 @@ int rcc_osc_ready_int_flag(osc_t osc)
return -1;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Clear the Clock Security System Interrupt Flag
+
+*/
+
void rcc_css_int_clear(void)
{
RCC_CIR |= RCC_CIR_CSSC;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Read the Clock Security System Interrupt Flag
+
+@returns int. Boolean value for flag set.
+*/
+
int rcc_css_int_flag(void)
{
return ((RCC_CIR & RCC_CIR_CSSF) != 0);
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Wait for Oscillator Ready.
+
+@param[in] osc enum ::osc_t. Oscillator ID
+*/
+
void rcc_wait_for_osc_ready(osc_t osc)
{
switch (osc) {
@@ -144,6 +218,20 @@ void rcc_wait_for_osc_ready(osc_t osc)
}
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Turn on an Oscillator.
+
+Enable an oscillator and power on. Each oscillator requires an amount of time to
+settle to a usable state. Refer to datasheets for time delay information. A status
+flag is available to indicate when the oscillator becomes ready (see
+@ref rcc_osc_ready_int_flag and @ref rcc_wait_for_osc_ready).
+
+@note The LSE clock is in the backup domain and cannot be enabled until the
+backup domain write protection has been removed (see @ref pwr_disable_backup_domain_write_protect).
+
+@param[in] osc enum ::osc_t. Oscillator ID
+*/
+
void rcc_osc_on(osc_t osc)
{
switch (osc) {
@@ -165,6 +253,20 @@ void rcc_osc_on(osc_t osc)
}
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Turn off an Oscillator.
+
+Disable an oscillator and power off.
+
+@note An oscillator cannot be turned off if it is selected as the system clock.
+@note The LSE clock is in the backup domain and cannot be disabled until the
+backup domain write protection has been removed (see
+@ref pwr_disable_backup_domain_write_protect) or the backup domain has been
+(see reset @ref rcc_backupdomain_reset).
+
+@param[in] osc enum ::osc_t. Oscillator ID
+*/
+
void rcc_osc_off(osc_t osc)
{
switch (osc) {
@@ -186,16 +288,39 @@ void rcc_osc_off(osc_t osc)
}
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Enable the Clock Security System.
+
+*/
+
void rcc_css_enable(void)
{
RCC_CR |= RCC_CR_CSSON;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Disable the Clock Security System.
+
+*/
+
void rcc_css_disable(void)
{
RCC_CR &= ~RCC_CR_CSSON;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Enable Bypass.
+
+Enable an external clock to bypass the internal clock (high speed and low speed
+clocks only). The external clock must be enabled (see @ref rcc_osc_on)
+and the internal clock must be disabled (see @ref rcc_osc_off) for this to have effect.
+
+@note The LSE clock is in the backup domain and cannot be bypassed until the
+backup domain write protection has been removed (see @ref pwr_disable_backup_domain_write_protect).
+
+@param[in] osc enum ::osc_t. Oscillator ID. Only HSE and LSE have effect.
+*/
+
void rcc_osc_bypass_enable(osc_t osc)
{
switch (osc) {
@@ -213,6 +338,19 @@ void rcc_osc_bypass_enable(osc_t osc)
}
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Disable Bypass.
+
+Re-enable the internal clock (high speed and low speed clocks only). The internal
+clock must be disabled (see @ref rcc_osc_off) for this to have effect.
+
+@note The LSE clock is in the backup domain and cannot have bypass removed until the
+backup domain write protection has been removed (see @ref pwr_disable_backup_domain_write_protect)
+or the backup domain has been reset (see @ref rcc_backupdomain_reset).
+
+@param[in] osc enum ::osc_t. Oscillator ID. Only HSE and LSE have effect.
+*/
+
void rcc_osc_bypass_disable(osc_t osc)
{
switch (osc) {
@@ -230,26 +368,96 @@ void rcc_osc_bypass_disable(osc_t osc)
}
}
+/*-----------------------------------------------------------------------------*/
+/** @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 u32 *reg, u32 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 u32 *reg, u32 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 u32 *reg, u32 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 u32 *reg, u32 clear_reset)
{
*reg &= ~clear_reset;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set the Source for the System Clock.
+
+@param[in] clk Unsigned int32. System Clock Selection @ref rcc_cfgr_scs
+*/
+
void rcc_set_sysclk_source(u32 clk)
{
u32 reg32;
@@ -259,6 +467,14 @@ void rcc_set_sysclk_source(u32 clk)
RCC_CFGR = (reg32 | clk);
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set the PLL Multiplication Factor.
+
+@note This only has effect when the PLL is disabled.
+
+@param[in] mul Unsigned int32. PLL multiplication factor @ref rcc_cfgr_pmf
+*/
+
void rcc_set_pll_multiplication_factor(u32 mul)
{
u32 reg32;
@@ -268,6 +484,14 @@ void rcc_set_pll_multiplication_factor(u32 mul)
RCC_CFGR = (reg32 | (mul << 18));
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set the PLL Clock Source.
+
+@note This only has effect when the PLL is disabled.
+
+@param[in] pllsrc Unsigned int32. PLL clock source @ref rcc_cfgr_pcs
+*/
+
void rcc_set_pll_source(u32 pllsrc)
{
u32 reg32;
@@ -277,6 +501,14 @@ void rcc_set_pll_source(u32 pllsrc)
RCC_CFGR = (reg32 | (pllsrc << 16));
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set the HSE Frequency Divider used as PLL Clock Source.
+
+@note This only has effect when the PLL is disabled.
+
+@param[in] pllxtpre Unsigned int32. HSE division factor @ref rcc_cfgr_hsepre
+*/
+
void rcc_set_pllxtpre(u32 pllxtpre)
{
u32 reg32;
@@ -286,6 +518,14 @@ void rcc_set_pllxtpre(u32 pllxtpre)
RCC_CFGR = (reg32 | (pllxtpre << 17));
}
+/*-----------------------------------------------------------------------------*/
+/** @brief ADC Setup the A/D Clock
+
+The ADC's have a common clock prescale setting.
+
+@param[in] adcpre u32. Prescale divider taken from @ref rcc_cfgr_adcpre
+*/
+
void rcc_set_adcpre(u32 adcpre)
{
u32 reg32;
@@ -295,6 +535,12 @@ void rcc_set_adcpre(u32 adcpre)
RCC_CFGR = (reg32 | (adcpre << 14));
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set the APB2 Prescale Factor.
+
+@param[in] ppre2 Unsigned int32. APB2 prescale factor @ref rcc_cfgr_apb2pre
+*/
+
void rcc_set_ppre2(u32 ppre2)
{
u32 reg32;
@@ -304,6 +550,14 @@ void rcc_set_ppre2(u32 ppre2)
RCC_CFGR = (reg32 | (ppre2 << 11));
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set the APB1 Prescale Factor.
+
+@note The APB1 clock frequency must not exceed 36MHz.
+
+@param[in] ppre1 Unsigned int32. APB1 prescale factor @ref rcc_cfgr_apb1pre
+*/
+
void rcc_set_ppre1(u32 ppre1)
{
u32 reg32;
@@ -313,6 +567,12 @@ void rcc_set_ppre1(u32 ppre1)
RCC_CFGR = (reg32 | (ppre1 << 8));
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set the AHB Prescale Factor.
+
+@param[in] hpre Unsigned int32. AHB prescale factor @ref rcc_cfgr_ahbpre
+*/
+
void rcc_set_hpre(u32 hpre)
{
u32 reg32;
@@ -322,6 +582,17 @@ void rcc_set_hpre(u32 hpre)
RCC_CFGR = (reg32 | (hpre << 4));
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set the USB Prescale Factor.
+
+The prescale factor can be set to 1 (no prescale) for use when the PLL clock is
+48MHz, or 1.5 to generate the 48MHz USB clock from a 64MHz PLL clock.
+
+@note This bit cannot be reset while the USB clock is enabled.
+
+@param[in] usbpre Unsigned int32. USB prescale factor @ref rcc_cfgr_usbpre
+*/
+
void rcc_set_usbpre(u32 usbpre)
{
u32 reg32;
@@ -331,16 +602,31 @@ void rcc_set_usbpre(u32 usbpre)
RCC_CFGR = (reg32 | (usbpre << 22));
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Get the System Clock Source.
+
+@returns Unsigned int32. System clock source:
+@li 00 indicates HSE
+@li 01 indicates LSE
+@li 02 indicates PLL
+*/
+
u32 rcc_system_clock_source(void)
{
/* Return the clock source which is used as system clock. */
return ((RCC_CFGR & 0x000c) >> 2);
}
+/*-----------------------------------------------------------------------------*/
/*
* These functions are setting up the whole clock system for the most common
* input clock and output clock configurations.
*/
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set System Clock PLL at 64MHz from HSI
+
+*/
+
void rcc_clock_setup_in_hsi_out_64mhz(void)
{
/* Enable internal high-speed oscillator. */
@@ -388,6 +674,11 @@ void rcc_clock_setup_in_hsi_out_64mhz(void)
rcc_ppre2_frequency = 64000000;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set System Clock PLL at 48MHz from HSI
+
+*/
+
void rcc_clock_setup_in_hsi_out_48mhz(void)
{
/* Enable internal high-speed oscillator. */
@@ -436,6 +727,62 @@ void rcc_clock_setup_in_hsi_out_48mhz(void)
rcc_ppre2_frequency = 48000000;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set System Clock PLL at 24MHz from HSI
+
+*/
+
+void rcc_clock_setup_in_hsi_out_24mhz(void) {
+ /* Enable internal high-speed oscillator. */
+ rcc_osc_on(HSI);
+ rcc_wait_for_osc_ready(HSI);
+
+ /* Select HSI as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
+
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /* Set. 24MHz Max. 24MHz */
+ rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV2); /* Set. 12MHz Max. 12MHz */
+ rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_NODIV); /* Set. 24MHz Max. 24MHz */
+ rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /* Set. 24MHz Max. 24MHz */
+
+ /*
+ * Sysclk is (will be) running with 24MHz -> 2 waitstates.
+ * 0WS from 0-24MHz
+ * 1WS from 24-48MHz
+ * 2WS from 48-72MHz
+ */
+ flash_set_ws(FLASH_LATENCY_0WS);
+
+ /*
+ * Set the PLL multiplication factor to 6.
+ * 8MHz (internal) * 6 (multiplier) / 2 (PLLSRC_HSI_CLK_DIV2) = 24MHz
+ */
+ rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL6);
+
+ /* Select HSI/2 as PLL source. */
+ rcc_set_pll_source(RCC_CFGR_PLLSRC_HSI_CLK_DIV2);
+
+ /* Enable PLL oscillator and wait for it to stabilize. */
+ rcc_osc_on(PLL);
+ rcc_wait_for_osc_ready(PLL);
+
+ /* Select PLL as SYSCLK source. */
+ rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
+
+ /* Set the peripheral clock frequencies used */
+ rcc_ppre1_frequency = 24000000;
+ rcc_ppre2_frequency = 24000000;
+}
+
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set System Clock PLL at 24MHz from HSE at 8MHz
+
+*/
+
void rcc_clock_setup_in_hse_8mhz_out_24mhz(void)
{
/* Enable internal high-speed oscillator. */
@@ -494,6 +841,11 @@ void rcc_clock_setup_in_hse_8mhz_out_24mhz(void)
rcc_ppre2_frequency = 24000000;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set System Clock PLL at 72MHz from HSE at 8MHz
+
+*/
+
void rcc_clock_setup_in_hse_8mhz_out_72mhz(void)
{
/* Enable internal high-speed oscillator. */
@@ -552,6 +904,11 @@ void rcc_clock_setup_in_hse_8mhz_out_72mhz(void)
rcc_ppre2_frequency = 72000000;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set System Clock PLL at 24MHz from HSE at 12MHz
+
+*/
+
void rcc_clock_setup_in_hse_12mhz_out_72mhz(void)
{
/* Enable internal high-speed oscillator. */
@@ -610,6 +967,11 @@ void rcc_clock_setup_in_hse_12mhz_out_72mhz(void)
rcc_ppre2_frequency = 72000000;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Set System Clock PLL at 24MHz from HSE at 16MHz
+
+*/
+
void rcc_clock_setup_in_hse_16mhz_out_72mhz(void)
{
/* Enable internal high-speed oscillator. */
@@ -668,6 +1030,12 @@ void rcc_clock_setup_in_hse_16mhz_out_72mhz(void)
rcc_ppre2_frequency = 72000000;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief RCC Reset the backup domain
+
+The backup domain register is reset to disable all controls.
+*/
+
void rcc_backupdomain_reset(void)
{
/* Set the backup domain software reset. */
@@ -676,3 +1044,5 @@ void rcc_backupdomain_reset(void)
/* Clear the backup domain software reset. */
RCC_BDCR &= ~RCC_BDCR_BDRST;
}
+/**@}*/
+
diff --git a/lib/stm32/f1/stm32f100x4.ld b/lib/stm32/f1/stm32f100x4.ld
new file mode 100644
index 0000000..4c86aee
--- /dev/null
+++ b/lib/stm32/f1/stm32f100x4.ld
@@ -0,0 +1,31 @@
+/*
+ * 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/>.
+ */
+
+/* Linker script for STM32F100x4, 16K flash, 4K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 16K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 4K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f1.ld
+
diff --git a/lib/stm32/f1/stm32f100x6.ld b/lib/stm32/f1/stm32f100x6.ld
new file mode 100644
index 0000000..23f77f3
--- /dev/null
+++ b/lib/stm32/f1/stm32f100x6.ld
@@ -0,0 +1,31 @@
+/*
+ * 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/>.
+ */
+
+/* Linker script for STM32F100x6, 32K flash, 4K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 32K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 4K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f1.ld
+
diff --git a/lib/stm32/f1/stm32f100x8.ld b/lib/stm32/f1/stm32f100x8.ld
new file mode 100644
index 0000000..e0aa041
--- /dev/null
+++ b/lib/stm32/f1/stm32f100x8.ld
@@ -0,0 +1,31 @@
+/*
+ * 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/>.
+ */
+
+/* Linker script for STM32F100x8, 64K flash, 8K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f1.ld
+
diff --git a/lib/stm32/f1/stm32f100xb.ld b/lib/stm32/f1/stm32f100xb.ld
new file mode 100644
index 0000000..83d64fd
--- /dev/null
+++ b/lib/stm32/f1/stm32f100xb.ld
@@ -0,0 +1,31 @@
+/*
+ * 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/>.
+ */
+
+/* Linker script for STM32F100xB, 128K flash, 8K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f1.ld
+
diff --git a/lib/stm32/f1/stm32f100xc.ld b/lib/stm32/f1/stm32f100xc.ld
new file mode 100644
index 0000000..30a894a
--- /dev/null
+++ b/lib/stm32/f1/stm32f100xc.ld
@@ -0,0 +1,31 @@
+/*
+ * 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/>.
+ */
+
+/* Linker script for STM32F100xC, 256K flash, 24K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 256K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 24K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f1.ld
+
diff --git a/lib/stm32/f1/stm32f100xd.ld b/lib/stm32/f1/stm32f100xd.ld
new file mode 100644
index 0000000..b507435
--- /dev/null
+++ b/lib/stm32/f1/stm32f100xd.ld
@@ -0,0 +1,31 @@
+/*
+ * 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/>.
+ */
+
+/* Linker script for STM32F100xD, 384K flash, 32K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 384K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f1.ld
+
diff --git a/lib/stm32/f1/stm32f100xe.ld b/lib/stm32/f1/stm32f100xe.ld
new file mode 100644
index 0000000..a12d1ff
--- /dev/null
+++ b/lib/stm32/f1/stm32f100xe.ld
@@ -0,0 +1,31 @@
+/*
+ * 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/>.
+ */
+
+/* Linker script for STM32F100xE, 512K flash, 32K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f1.ld
+
diff --git a/lib/stm32/f1/timer.c b/lib/stm32/f1/timer.c
index cf5b411..c5ea921 100644
--- a/lib/stm32/f1/timer.c
+++ b/lib/stm32/f1/timer.c
@@ -1,3 +1,71 @@
+/** @defgroup STM32F1xx-timer-file Timers
+
+@ingroup STM32F1xx
+
+@brief <b>libopencm3 STM32F1xx Timers</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2010 Edward Cheeseman <evbuilder@users.sourceforge.org>
+
+@date 18 August 2012
+
+This library supports the General Purpose and Advanced Control Timers for
+the STM32F1xx series of ARM Cortex Microcontrollers by ST Microelectronics.
+
+The STM32F1xx 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.
*
@@ -25,9 +93,22 @@
* TIM_CR1_CMS_CENTRE_3, TIM_CR1_DIR_UP);
*/
+/**@{*/
+
#include <libopencm3/stm32/timer.h>
#include <libopencm3/stm32/f1/rcc.h>
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral)
{
switch (timer_peripheral) {
@@ -93,31 +174,84 @@ void timer_reset(u32 timer_peripheral)
}
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, u32 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(u32 timer_peripheral, u32 irq)
{
TIM_DIER(timer_peripheral) &= ~irq;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, u32 flag)
{
- if (((TIM_SR(timer_peripheral) & flag) != 0) &&
- ((TIM_DIER(timer_peripheral) & flag) != 0)) {
+ 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(u32 timer_peripheral, u32 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(u32 timer_peripheral, u32 clock_div,
u32 alignment, u32 direction)
{
@@ -132,6 +266,16 @@ void timer_set_mode(u32 timer_peripheral, u32 clock_div,
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(u32 timer_peripheral, u32 clock_div)
{
clock_div &= TIM_CR1_CKD_CK_INT_MASK;
@@ -139,16 +283,44 @@ void timer_set_clock_division(u32 timer_peripheral, u32 clock_div)
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(u32 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(u32 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(u32 timer_peripheral, u32 alignment)
{
alignment &= TIM_CR1_CMS_MASK;
@@ -156,128 +328,369 @@ void timer_set_alignment(u32 timer_peripheral, u32 alignment)
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(u32 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(u32 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(u32 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(u32 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(u32 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(u32 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(u32 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(u32 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(u32 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(u32 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(u32 timer_peripheral, u32 outputs)
{
- TIM_CR2(timer_peripheral) |= outputs & TIM_CR2_OIS_MASK;
+ if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
+ TIM_CR2(timer_peripheral) |= outputs & TIM_CR2_OIS_MASK;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, u32 outputs)
{
- TIM_CR2(timer_peripheral) &= ~(outputs & TIM_CR2_OIS_MASK);
+ if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
+ TIM_CR2(timer_peripheral) &= ~(outputs & TIM_CR2_OIS_MASK);
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 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(u32 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(u32 timer_peripheral, u32 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(u32 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(u32 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(u32 timer_peripheral)
{
- TIM_CR2(timer_peripheral) |= TIM_CR2_CCUS;
+ if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
+ TIM_CR2(timer_peripheral) |= TIM_CR2_CCUS;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral)
{
- TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCUS;
+ if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCUS;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral)
{
- TIM_CR2(timer_peripheral) |= TIM_CR2_CCPC;
+ if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
+ TIM_CR2(timer_peripheral) |= TIM_CR2_CCPC;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral)
{
- TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCPC;
+ if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
+ TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCPC;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, u32 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(u32 timer_peripheral, u32 value)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_RCR(timer_peripheral) = value;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, u32 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(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
@@ -296,11 +709,19 @@ void timer_enable_oc_clear(u32 timer_peripheral, enum tim_oc_id oc_id)
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
- /* Ignoring as fast enable only applies to the whole channel. */
+ /* 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(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
@@ -319,11 +740,24 @@ void timer_disable_oc_clear(u32 timer_peripheral, enum tim_oc_id oc_id)
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
- /* Ignoring as fast enable only applies to the whole channel. */
+ /* 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(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
@@ -347,6 +781,17 @@ void timer_set_oc_fast_mode(u32 timer_peripheral, enum tim_oc_id oc_id)
}
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
@@ -370,6 +815,29 @@ void timer_set_oc_slow_mode(u32 timer_peripheral, enum tim_oc_id oc_id)
}
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_oc_id oc_id,
enum tim_oc_mode oc_mode)
{
@@ -510,6 +978,14 @@ void timer_set_oc_mode(u32 timer_peripheral, enum tim_oc_id oc_id,
}
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
@@ -533,6 +1009,14 @@ void timer_enable_oc_preload(u32 timer_peripheral, enum tim_oc_id oc_id)
}
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
@@ -556,6 +1040,16 @@ void timer_disable_oc_preload(u32 timer_peripheral, enum tim_oc_id oc_id)
}
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
@@ -601,6 +1095,16 @@ void timer_set_oc_polarity_high(u32 timer_peripheral, enum tim_oc_id oc_id)
}
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
@@ -646,6 +1150,16 @@ void timer_set_oc_polarity_low(u32 timer_peripheral, enum tim_oc_id oc_id)
}
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
@@ -691,6 +1205,16 @@ void timer_enable_oc_output(u32 timer_peripheral, enum tim_oc_id oc_id)
}
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
@@ -736,6 +1260,19 @@ void timer_disable_oc_output(u32 timer_peripheral, enum tim_oc_id oc_id)
}
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_oc_id oc_id)
{
/* Acting for TIM1 and TIM8 only. */
@@ -767,6 +1304,19 @@ void timer_set_oc_idle_state_set(u32 timer_peripheral, enum tim_oc_id oc_id)
}
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_oc_id oc_id)
{
/* Acting for TIM1 and TIM8 only. */
@@ -798,6 +1348,19 @@ void timer_set_oc_idle_state_unset(u32 timer_peripheral, enum tim_oc_id oc_id)
}
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_oc_id oc_id, u32 value)
{
switch (oc_id) {
@@ -821,145 +1384,382 @@ void timer_set_oc_value(u32 timer_peripheral, enum tim_oc_id oc_id, u32 value)
}
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_MOE;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_MOE;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_AOE;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_AOE;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_BKP;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_BKP;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_BKE;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_BKE;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_OSSR;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_OSSR;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_OSSI;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_OSSI;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, u32 lock)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= lock;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, u32 deadtime)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= deadtime;
}
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, u32 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.
+*/
+
u32 timer_get_counter(u32 timer_peripheral)
{
return TIM_CNT(timer_peripheral);
}
-void timer_ic_set_filter(u32 timer, enum tim_ic_id ic, enum tim_ic_filter flt)
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_ic_id ic, enum tim_ic_filter flt)
{
switch (ic) {
case TIM_IC1:
- TIM_CCMR1(timer) &= ~TIM_CCMR1_IC1F_MASK;
- TIM_CCMR1(timer) |= flt << 4;
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_IC1F_MASK;
+ TIM_CCMR1(timer_peripheral) |= flt << 4;
break;
case TIM_IC2:
- TIM_CCMR1(timer) &= ~TIM_CCMR1_IC2F_MASK;
- TIM_CCMR1(timer) |= flt << 12;
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_IC2F_MASK;
+ TIM_CCMR1(timer_peripheral) |= flt << 12;
break;
case TIM_IC3:
- TIM_CCMR2(timer) &= ~TIM_CCMR2_IC3F_MASK;
- TIM_CCMR2(timer) |= flt << 4;
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_IC3F_MASK;
+ TIM_CCMR2(timer_peripheral) |= flt << 4;
break;
case TIM_IC4:
- TIM_CCMR2(timer) &= ~TIM_CCMR2_IC4F_MASK;
- TIM_CCMR2(timer) |= flt << 12;
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_IC4F_MASK;
+ TIM_CCMR2(timer_peripheral) |= flt << 12;
break;
}
}
-void timer_ic_set_prescaler(u32 timer, enum tim_ic_id ic, enum tim_ic_psc psc)
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_ic_id ic, enum tim_ic_psc psc)
{
switch (ic) {
case TIM_IC1:
- TIM_CCMR1(timer) &= ~TIM_CCMR1_IC1PSC_MASK;
- TIM_CCMR1(timer) |= psc << 2;
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_IC1PSC_MASK;
+ TIM_CCMR1(timer_peripheral) |= psc << 2;
break;
case TIM_IC2:
- TIM_CCMR1(timer) &= ~TIM_CCMR1_IC2PSC_MASK;
- TIM_CCMR1(timer) |= psc << 10;
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_IC2PSC_MASK;
+ TIM_CCMR1(timer_peripheral) |= psc << 10;
break;
case TIM_IC3:
- TIM_CCMR2(timer) &= ~TIM_CCMR2_IC3PSC_MASK;
- TIM_CCMR2(timer) |= psc << 4;
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_IC3PSC_MASK;
+ TIM_CCMR2(timer_peripheral) |= psc << 4;
break;
case TIM_IC4:
- TIM_CCMR2(timer) &= ~TIM_CCMR2_IC4PSC_MASK;
- TIM_CCMR2(timer) |= psc << 10;
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_IC4PSC_MASK;
+ TIM_CCMR2(timer_peripheral) |= psc << 10;
break;
}
}
-void timer_ic_set_input(u32 timer, enum tim_ic_id ic, enum tim_ic_input in)
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_ic_id ic, enum tim_ic_input in)
{
in &= 3;
@@ -971,71 +1771,139 @@ void timer_ic_set_input(u32 timer, enum tim_ic_id ic, enum tim_ic_input in)
switch (ic) {
case TIM_IC1:
- TIM_CCMR1(timer) &= ~TIM_CCMR1_CC1S_MASK;
- TIM_CCMR1(timer) |= in;
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC1S_MASK;
+ TIM_CCMR1(timer_peripheral) |= in;
break;
case TIM_IC2:
- TIM_CCMR1(timer) &= ~TIM_CCMR1_CC2S_MASK;
- TIM_CCMR1(timer) |= in << 8;
+ TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC2S_MASK;
+ TIM_CCMR1(timer_peripheral) |= in << 8;
break;
case TIM_IC3:
- TIM_CCMR2(timer) &= ~TIM_CCMR2_CC3S_MASK;
- TIM_CCMR2(timer) |= in;
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_CC3S_MASK;
+ TIM_CCMR2(timer_peripheral) |= in;
break;
case TIM_IC4:
- TIM_CCMR2(timer) &= ~TIM_CCMR2_CC4S_MASK;
- TIM_CCMR2(timer) |= in << 8;
+ TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_CC4S_MASK;
+ TIM_CCMR2(timer_peripheral) |= in << 8;
break;
}
}
-void timer_ic_set_polarity(u32 timer, enum tim_ic_id ic, enum tim_ic_pol pol)
+/*---------------------------------------------------------------------------*/
+/** @brief Set Input Polarity
+
+@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.
+*/
+
+void timer_ic_set_polarity(u32 timer_peripheral, enum tim_ic_id ic, enum tim_ic_pol pol)
{
if (pol)
- TIM_CCER(timer) |= (0x2 << (ic * 4));
+ TIM_CCER(timer_peripheral) |= (0x2 << (ic * 4));
else
- TIM_CCER(timer) &= ~(0x2 << (ic * 4));
+ TIM_CCER(timer_peripheral) &= ~(0x2 << (ic * 4));
}
-void timer_ic_enable(u32 timer, enum tim_ic_id ic)
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_ic_id ic)
{
- TIM_CCER(timer) |= (0x1 << (ic * 4));
+ TIM_CCER(timer_peripheral) |= (0x1 << (ic * 4));
}
-void timer_ic_disable(u32 timer, enum tim_ic_id ic)
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_ic_id ic)
{
- TIM_CCER(timer) &= ~(0x1 << (ic * 4));
+ TIM_CCER(timer_peripheral) &= ~(0x1 << (ic * 4));
}
-void timer_slave_set_filter(u32 timer, enum tim_ic_filter flt)
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_ic_filter flt)
{
- TIM_SMCR(timer) &= ~TIM_SMCR_ETF_MASK;
- TIM_SMCR(timer) |= flt << 8;
+ TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_ETF_MASK;
+ TIM_SMCR(timer_peripheral) |= flt << 8;
}
-void timer_slave_set_prescaler(u32 timer, enum tim_ic_psc psc)
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, enum tim_ic_psc psc)
{
- TIM_SMCR(timer) &= ~TIM_SMCR_ETPS_MASK;
- TIM_SMCR(timer) |= psc << 12;
+ TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_ETPS_MASK;
+ TIM_SMCR(timer_peripheral) |= psc << 12;
}
-void timer_slave_set_polarity(u32 timer, enum tim_ic_pol pol)
+/*---------------------------------------------------------------------------*/
+/** @brief Set External Trigger Polarity for Slave
+
+@param[in] timer_peripheral Unsigned int32. Timer register address base
+@param[in] pol ::tim_ic_pol. Input Capture polarity.
+*/
+
+void timer_slave_set_polarity(u32 timer_peripheral, enum tim_ic_pol pol)
{
if (pol)
- TIM_SMCR(timer) |= TIM_SMCR_ETP;
+ TIM_SMCR(timer_peripheral) |= TIM_SMCR_ETP;
else
- TIM_SMCR(timer) &= ~TIM_SMCR_ETP;
+ TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_ETP;
}
-void timer_slave_set_mode(u32 timer, u8 mode)
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, u8 mode)
{
- TIM_SMCR(timer) &= ~TIM_SMCR_SMS_MASK;
- TIM_SMCR(timer) |= mode;
+ TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_SMS_MASK;
+ TIM_SMCR(timer_peripheral) |= mode;
}
-void timer_slave_set_trigger(u32 timer, u8 trigger)
+/*---------------------------------------------------------------------------*/
+/** @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(u32 timer_peripheral, u8 trigger)
{
- TIM_SMCR(timer) &= ~TIM_SMCR_TS_MASK;
- TIM_SMCR(timer) |= trigger;
+ TIM_SMCR(timer_peripheral) &= ~TIM_SMCR_TS_MASK;
+ TIM_SMCR(timer_peripheral) |= trigger;
}
+/* TODO Timer DMA burst */
+
+/**@}*/
+
diff --git a/lib/stm32/f1/vector.c b/lib/stm32/f1/vector.c
index 119ce30..f496ae4 100644
--- a/lib/stm32/f1/vector.c
+++ b/lib/stm32/f1/vector.c
@@ -19,8 +19,8 @@
#define WEAK __attribute__ ((weak))
-/* Symbols exported by the linker script(s). */
-extern unsigned __exidx_end, _data, _edata, _ebss, _stack;
+/* Symbols exported by the linker script(s): */
+extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
void main(void);
void reset_handler(void);
@@ -197,7 +197,7 @@ void reset_handler(void)
__asm__("MSR msp, %0" : : "r"(&_stack));
- for (src = &__exidx_end, dest = &_data; dest < &_edata; src++, dest++)
+ for (src = &_data_loadaddr, dest = &_data; dest < &_edata; src++, dest++)
*dest = *src;
while (dest < &_ebss)
diff --git a/lib/stm32/f2/Makefile b/lib/stm32/f2/Makefile
index e0f8d95..bd6f275 100644
--- a/lib/stm32/f2/Makefile
+++ b/lib/stm32/f2/Makefile
@@ -33,27 +33,4 @@ OBJS = vector.o rcc.o gpio.o usart.o spi.o flash.o nvic.o \
VPATH += ../../usb:../
-# Be silent per default, but 'make V=1' will show all compiler calls.
-ifneq ($(V),1)
-Q := @
-endif
-
-all: $(LIBNAME).a
-
-$(LIBNAME).a: $(OBJS)
- @printf " AR $(subst $(shell pwd)/,,$(@))\n"
- $(Q)$(AR) $(ARFLAGS) $@ $^
-
-%.o: %.c
- @printf " CC $(subst $(shell pwd)/,,$(@))\n"
- $(Q)$(CC) $(CFLAGS) -o $@ -c $<
-
-clean:
- @printf " CLEAN lib/stm32/f2\n"
- $(Q)rm -f *.o *.d
- $(Q)rm -f $(LIBNAME).a
-
-.PHONY: clean
-
--include $(OBJS:.o=.d)
-
+include ../../Makefile.include
diff --git a/lib/stm32/f2/gpio.c b/lib/stm32/f2/gpio.c
index 7a38120..984cddb 100644
--- a/lib/stm32/f2/gpio.c
+++ b/lib/stm32/f2/gpio.c
@@ -111,7 +111,7 @@ u16 gpio_get(u32 gpioport, u16 gpios)
void gpio_toggle(u32 gpioport, u16 gpios)
{
- GPIO_ODR(gpioport) = GPIO_IDR(gpioport) ^ gpios;
+ GPIO_ODR(gpioport) ^= gpios;
}
u16 gpio_port_read(u32 gpioport)
@@ -135,5 +135,8 @@ void gpio_port_config_lock(u32 gpioport, u16 gpios)
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/lib/stm32/f2/libopencm3_stm32f2.ld b/lib/stm32/f2/libopencm3_stm32f2.ld
index a64a1f7..9d165f6 100644
--- a/lib/stm32/f2/libopencm3_stm32f2.ld
+++ b/lib/stm32/f2/libopencm3_stm32f2.ld
@@ -30,21 +30,18 @@ ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
- . = ORIGIN(rom);
-
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
- _etext = .;
} >rom
/*
- * Another section used by C++ stuff, appears when using newlib with
- * 64bit (long long) printf support
- */
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
.ARM.extab : {
*(.ARM.extab*)
} >rom
@@ -54,21 +51,23 @@ SECTIONS
__exidx_end = .;
} >rom
- . = ORIGIN(ram);
+ . = ALIGN(4);
+ _etext = .;
- .data : AT (__exidx_end) {
+ .data : {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
- } >ram
+ } >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
- } >ram AT >rom
+ } >ram
/*
* The .eh_frame section appears to be used for C++ exception handling.
diff --git a/lib/stm32/f2/vector.c b/lib/stm32/f2/vector.c
index 64d2426..3429bfb 100644
--- a/lib/stm32/f2/vector.c
+++ b/lib/stm32/f2/vector.c
@@ -21,7 +21,7 @@
#define WEAK __attribute__ ((weak))
/* Symbols exported by the linker script(s): */
-extern unsigned __exidx_end, _data, _edata, _ebss, _stack;
+extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
void main(void);
void reset_handler(void);
@@ -224,7 +224,7 @@ void reset_handler(void)
__asm__("MSR msp, %0" : : "r"(&_stack));
- for (src = &__exidx_end, dest = &_data; dest < &_edata; src++, dest++)
+ for (src = &_data_loadaddr, dest = &_data; dest < &_edata; src++, dest++)
*dest = *src;
while (dest < &_ebss)
diff --git a/lib/stm32/f4/Makefile b/lib/stm32/f4/Makefile
index f8b4dd2..5760d29 100644
--- a/lib/stm32/f4/Makefile
+++ b/lib/stm32/f4/Makefile
@@ -34,27 +34,4 @@ OBJS = vector.o rcc.o gpio.o usart.o spi.o flash.o nvic.o \
VPATH += ../../usb:../
-# Be silent per default, but 'make V=1' will show all compiler calls.
-ifneq ($(V),1)
-Q := @
-endif
-
-all: $(LIBNAME).a
-
-$(LIBNAME).a: $(OBJS)
- @printf " AR $(subst $(shell pwd)/,,$(@))\n"
- $(Q)$(AR) $(ARFLAGS) $@ $^
-
-%.o: %.c
- @printf " CC $(subst $(shell pwd)/,,$(@))\n"
- $(Q)$(CC) $(CFLAGS) -o $@ -c $<
-
-clean:
- @printf " CLEAN lib/stm32/f4\n"
- $(Q)rm -f *.o *.d
- $(Q)rm -f $(LIBNAME).a
-
-.PHONY: clean
-
--include $(OBJS:.o=.d)
-
+include ../../Makefile.include
diff --git a/lib/stm32/f4/gpio.c b/lib/stm32/f4/gpio.c
index dea3720..1d7739d 100644
--- a/lib/stm32/f4/gpio.c
+++ b/lib/stm32/f4/gpio.c
@@ -111,7 +111,7 @@ u16 gpio_get(u32 gpioport, u16 gpios)
void gpio_toggle(u32 gpioport, u16 gpios)
{
- GPIO_ODR(gpioport) = GPIO_IDR(gpioport) ^ gpios;
+ GPIO_ODR(gpioport) ^= gpios;
}
u16 gpio_port_read(u32 gpioport)
@@ -135,5 +135,8 @@ void gpio_port_config_lock(u32 gpioport, u16 gpios)
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/lib/stm32/f4/libopencm3_stm32f4.ld b/lib/stm32/f4/libopencm3_stm32f4.ld
index 0624b96..9d165f6 100644
--- a/lib/stm32/f4/libopencm3_stm32f4.ld
+++ b/lib/stm32/f4/libopencm3_stm32f4.ld
@@ -30,8 +30,6 @@ ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
- . = ORIGIN(rom);
-
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
@@ -40,14 +38,20 @@ SECTIONS
. = ALIGN(4);
} >rom
- /* exception index - required due to libgcc.a issuing /0 exceptions */
- __exidx_start = .;
+ /*
+ * Another section used by C++ stuff, appears when using newlib with
+ * 64bit (long long) printf support
+ */
+ .ARM.extab : {
+ *(.ARM.extab*)
+ } >rom
.ARM.exidx : {
- *(.ARM.exidx*)
- } > rom
- __exidx_end = .;
-
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >rom
+ . = ALIGN(4);
_etext = .;
.data : {
@@ -56,6 +60,7 @@ SECTIONS
. = ALIGN(4);
_edata = .;
} >ram AT >rom
+ _data_loadaddr = LOADADDR(.data);
.bss : {
*(.bss*) /* Read-write zero initialized data */
@@ -64,10 +69,11 @@ SECTIONS
_ebss = .;
} >ram
- /* exception unwind data - required due to libgcc.a issuing /0 exceptions */
- .ARM.extab : {
- *(.ARM.extab*)
- } >ram
+ /*
+ * The .eh_frame section appears to be used for C++ exception handling.
+ * You may need to fix this if you're using C++.
+ */
+ /DISCARD/ : { *(.eh_frame) }
. = ALIGN(4);
end = .;
diff --git a/lib/stm32/f4/vector.c b/lib/stm32/f4/vector.c
index 1c901da..3429bfb 100644
--- a/lib/stm32/f4/vector.c
+++ b/lib/stm32/f4/vector.c
@@ -21,7 +21,7 @@
#define WEAK __attribute__ ((weak))
/* Symbols exported by the linker script(s): */
-extern unsigned _etext, _data, _edata, _ebss, _stack;
+extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
void main(void);
void reset_handler(void);
@@ -224,7 +224,7 @@ void reset_handler(void)
__asm__("MSR msp, %0" : : "r"(&_stack));
- for (src = &_etext, dest = &_data; dest < &_edata; src++, dest++)
+ for (src = &_data_loadaddr, dest = &_data; dest < &_edata; src++, dest++)
*dest = *src;
while (dest < &_ebss)
diff --git a/lib/stm32/iwdg.c b/lib/stm32/iwdg.c
new file mode 100644
index 0000000..251bec1
--- /dev/null
+++ b/lib/stm32/iwdg.c
@@ -0,0 +1,144 @@
+/** @defgroup STM32F_iwdg_file IWDG
+
+@ingroup STM32F_files
+
+@brief <b>libopencm3 STM32F1xx Independent Watchdog Timer</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies ksarkies@internode.on.net
+
+@date 18 August 2012
+
+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
+
+LGPL License Terms @ref lgpl_license
+ */
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**@{*/
+
+#include <libopencm3/stm32/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 u32 Period in milliseconds (< 32760) from a watchdog reset until
+a system reset is issued.
+*/
+
+void iwdg_set_period_ms(u32 period)
+{
+u32 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/lib/stm32/nvic.c b/lib/stm32/nvic.c
index cd823e1..84fa674 100644
--- a/lib/stm32/nvic.c
+++ b/lib/stm32/nvic.c
@@ -1,3 +1,26 @@
+/** @defgroup STM32F_nvic_file NVIC
+
+@ingroup STM32F_files
+
+@brief <b>libopencm3 STM32F Nested Vectored Interrupt Controller</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
+@author @htmlonly &copy; @endhtmlonly 2012 Fergus Noble <fergusnoble@gmail.com>
+
+@date 18 August 2012
+
+The STM32F series provides up to 68 maskable user interrupts for the STM32F10x
+series, and 87 for the STM32F2xx and STM32F4xx series.
+
+The NVIC registers are defined by the ARM standards but the STM32F series have some
+additional limitations
+@see Cortex-M3 Devices Generic User Guide
+@see STM32F10xxx Cortex-M3 programming manual
+
+LGPL License Terms @ref lgpl_license
+*/
/*
* This file is part of the libopencm3 project.
*
@@ -18,50 +41,134 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
+/**@{*/
+
#include <libopencm3/stm32/nvic.h>
+/*-----------------------------------------------------------------------------*/
+/** @brief NVIC Enable Interrupt
+
+Enables a user interrupt.
+
+@param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
+*/
+
void nvic_enable_irq(u8 irqn)
{
NVIC_ISER(irqn / 32) = (1 << (irqn % 32));
}
+/*-----------------------------------------------------------------------------*/
+/** @brief NVIC Disable Interrupt
+
+Disables a user interrupt.
+
+@param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
+*/
+
void nvic_disable_irq(u8 irqn)
{
NVIC_ICER(irqn / 32) = (1 << (irqn % 32));
}
+/*-----------------------------------------------------------------------------*/
+/** @brief NVIC Return Pending Interrupt
+
+True if the interrupt has occurred and is waiting for service.
+
+@param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
+@return Boolean. Interrupt pending.
+*/
+
u8 nvic_get_pending_irq(u8 irqn)
{
return NVIC_ISPR(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief NVIC Set Pending Interrupt
+
+Force a user interrupt to a pending state. This has no effect if the interrupt
+is already pending.
+
+@param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
+*/
+
void nvic_set_pending_irq(u8 irqn)
{
NVIC_ISPR(irqn / 32) = (1 << (irqn % 32));
}
+/*-----------------------------------------------------------------------------*/
+/** @brief NVIC Clear Pending Interrupt
+
+Force remove a user interrupt from a pending state. This has no effect if the
+interrupt is actively being serviced.
+
+@param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
+*/
+
void nvic_clear_pending_irq(u8 irqn)
{
NVIC_ICPR(irqn / 32) = (1 << (irqn % 32));
}
+/*-----------------------------------------------------------------------------*/
+/** @brief NVIC Return Active Interrupt
+
+Interrupt has occurred and is currently being serviced.
+
+@param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
+@return Boolean. Interrupt active.
+*/
+
u8 nvic_get_active_irq(u8 irqn)
{
return NVIC_IABR(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief NVIC Return Enabled Interrupt
+
+@param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
+@return Boolean. Interrupt enabled.
+*/
+
u8 nvic_get_irq_enabled(u8 irqn)
{
return NVIC_ISER(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief NVIC Set Interrupt Priority
+
+There are 16 priority levels only, given by the upper four bits of the priority
+byte, as required by ARM standards. The priority levels are interpreted according
+to the pre-emptive priority grouping set in the SCB Application Interrupt and Reset
+Control Register (SCB_AIRCR), as done in @ref scb_set_priority_grouping.
+
+@param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
+@param[in] priority Unsigned int8. Interrupt priority (0 ... 255 in steps of 16)
+*/
+
void nvic_set_priority(u8 irqn, u8 priority)
{
- NVIC_IPR(irqn / 4) |= (priority << ((irqn % 4) * 8));
+ NVIC_IPR(irqn) = priority;
}
-void nvic_generate_software_interrupt(u8 irqn)
+/*-----------------------------------------------------------------------------*/
+/** @brief NVIC Software Trigger Interrupt
+
+Generate an interrupt from software. This has no effect for unprivileged access
+unless the privilege level has been elevated through the System Control Registers.
+
+@param[in] irqn Unsigned int16. Interrupt number (0 ... 239)
+*/
+
+void nvic_generate_software_interrupt(u16 irqn)
{
if (irqn <= 239)
NVIC_STIR |= irqn;
}
+/**@}*/
+
diff --git a/lib/stm32/systick.c b/lib/stm32/systick.c
index c49d11d..36077cc 100644
--- a/lib/stm32/systick.c
+++ b/lib/stm32/systick.c
@@ -1,3 +1,23 @@
+/** @defgroup STM32F_systick_file SysTick
+
+@ingroup STM32F_files
+
+@brief <b>libopencm3 STM32Fxx System Tick Timer</b>
+
+@version 1.0.0
+
+@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
+
+@date 19 August 2012
+
+This library supports the System Tick timer in the
+STM32F series of ARM Cortex Microcontrollers by ST Microelectronics.
+
+The System Tick timer is part of the ARM Cortex core. It is a 24 bit
+down counter that can be configured with an automatical reload value.
+
+LGPL License Terms @ref lgpl_license
+ */
/*
* This file is part of the libopencm3 project.
*
@@ -17,44 +37,97 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
+/**@{*/
#include <libopencm3/stm32/systick.h>
+/*-----------------------------------------------------------------------------*/
+/** @brief SysTick Set the Automatic Reload Value.
+
+The counter is set to the reload value when the counter starts and after it
+reaches zero.
+
+@param[in] value u32. 24 bit reload value.
+*/
+
void systick_set_reload(u32 value)
{
STK_LOAD = (value & 0x00FFFFFF);
}
+/*-----------------------------------------------------------------------------*/
+/** @brief SysTick Read the Automatic Reload Value.
+
+@returns 24 bit reload value as u32.
+*/
+
u32 systick_get_value(void)
{
return STK_VAL;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief Set the SysTick Clock Source.
+
+The clock source can be either the AHB clock or the same clock divided by 8.
+
+@param[in] clocksource u8. Clock source from @ref systick_clksource.
+*/
+
void systick_set_clocksource(u8 clocksource)
{
if (clocksource < 2)
STK_CTRL |= (clocksource << STK_CTRL_CLKSOURCE_LSB);
}
+/*-----------------------------------------------------------------------------*/
+/** @brief Enable SysTick Interrupt.
+
+*/
+
void systick_interrupt_enable(void)
{
STK_CTRL |= STK_CTRL_TICKINT;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief Disable SysTick Interrupt.
+
+*/
+
void systick_interrupt_disable(void)
{
STK_CTRL &= ~STK_CTRL_TICKINT;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief Enable SysTick Counter.
+
+*/
+
void systick_counter_enable(void)
{
STK_CTRL |= STK_CTRL_ENABLE;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief Disable SysTick Counter.
+
+*/
+
void systick_counter_disable(void)
{
STK_CTRL &= ~STK_CTRL_ENABLE;
}
+/*-----------------------------------------------------------------------------*/
+/** @brief SysTick Read the Counter Flag.
+
+The count flag is set when the timer count becomes zero, and is cleared when the
+flag is read.
+
+@returns Boolean if flag set.
+*/
+
u8 systick_get_countflag(void)
{
if (STK_CTRL & STK_CTRL_COUNTFLAG)
@@ -62,3 +135,5 @@ u8 systick_get_countflag(void)
else
return 0;
}
+/**@}*/
+