subrepo:
  subdir:   "libopencm3"
  merged:   "88e91c9a7cce"
upstream:
  origin:   "https://github.com/libopencm3/libopencm3.git"
  branch:   "master"
  commit:   "88e91c9a7cce"
git-subrepo:
  version:  "0.4.3"
  origin:   "???"
  commit:   "???"
This commit is contained in:
2023-01-21 21:54:42 +02:00
parent f01f2a30fa
commit 054740c5de
1205 changed files with 191912 additions and 0 deletions

550
libopencm3/lib/stm32/can.c Normal file
View File

@@ -0,0 +1,550 @@
/** @defgroup can_file CAN
@ingroup STM32F_files
@brief <b>libopencm3 STM32Fxxx CAN</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2010 Piotr Esden-Tempski <piotr@esden.net>
@date 12 November 2012
Devices can have up to two CAN peripherals. The peripherals support up to 1MBit
transmission rate. The peripheral has several filters for incoming messages that
can be distributed between two FIFOs and three transmit mailboxes.
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.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/can.h>
#include <libopencm3/stm32/rcc.h>
/* Timeout for CAN INIT acknowledge
* this value is difficult to define.
* INIT is set latest after finishing the current transfer.
* Assuming the lowest CAN speed of 100kbps one CAN frame may take about 1.6ms
* WAIT loop timeout varies on compiler switches, optimization, CPU architecture
* and CPU speed
*
* The same timeout value is used for leaving INIT where the longest time is
* 11 bits(110 us on 100 kbps).
*/
#define CAN_MSR_INAK_TIMEOUT 0x0000FFFF
/*---------------------------------------------------------------------------*/
/** @brief CAN Reset
The CAN peripheral and all its associated configuration registers are placed in
the reset condition. The reset is effective via the RCC peripheral reset
system.
@param[in] canport Unsigned int32. CAN block register address base @ref
can_reg_base.
*/
void can_reset(uint32_t canport)
{
if (canport == CAN1) {
rcc_periph_reset_pulse(RST_CAN1);
} else {
#if defined(BX_CAN2_BASE)
rcc_periph_reset_pulse(RST_CAN2);
#endif
}
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Init
Initialize the selected CAN peripheral block.
@param[in] canport Unsigend int32. CAN register base address @ref can_reg_base.
@param[in] ttcm bool. Time triggered communication mode.
@param[in] abom bool. Automatic bus-off management.
@param[in] awum bool. Automatic wakeup mode.
@param[in] nart bool. No automatic retransmission.
@param[in] rflm bool. Receive FIFO locked mode.
@param[in] txfp bool. Transmit FIFO priority.
@param[in] sjw Unsigned int32. Resynchronization time quanta jump width.
@param[in] ts1 Unsigned int32. Time segment 1 time quanta width.
@param[in] ts2 Unsigned int32. Time segment 2 time quanta width.
@param[in] brp Unsigned int32. Baud rate prescaler.
@returns int 0 on success, 1 on initialization failure.
*/
int can_init(uint32_t canport, bool ttcm, bool abom, bool awum, bool nart,
bool rflm, bool txfp, uint32_t sjw, uint32_t ts1, uint32_t ts2,
uint32_t brp, bool loopback, bool silent)
{
volatile uint32_t wait_ack;
int ret = 0;
/* Exit from sleep mode. */
CAN_MCR(canport) &= ~CAN_MCR_SLEEP;
/* Request initialization "enter". */
CAN_MCR(canport) |= CAN_MCR_INRQ;
/* Wait for acknowledge. */
wait_ack = CAN_MSR_INAK_TIMEOUT;
while ((--wait_ack) &&
((CAN_MSR(canport) & CAN_MSR_INAK) != CAN_MSR_INAK));
/* Check the acknowledge. */
if ((CAN_MSR(canport) & CAN_MSR_INAK) != CAN_MSR_INAK) {
return 1;
}
/* clear can timing bits */
CAN_BTR(canport) = 0;
/* Set the automatic bus-off management. */
if (ttcm) {
CAN_MCR(canport) |= CAN_MCR_TTCM;
} else {
CAN_MCR(canport) &= ~CAN_MCR_TTCM;
}
if (abom) {
CAN_MCR(canport) |= CAN_MCR_ABOM;
} else {
CAN_MCR(canport) &= ~CAN_MCR_ABOM;
}
if (awum) {
CAN_MCR(canport) |= CAN_MCR_AWUM;
} else {
CAN_MCR(canport) &= ~CAN_MCR_AWUM;
}
if (nart) {
CAN_MCR(canport) |= CAN_MCR_NART;
} else {
CAN_MCR(canport) &= ~CAN_MCR_NART;
}
if (rflm) {
CAN_MCR(canport) |= CAN_MCR_RFLM;
} else {
CAN_MCR(canport) &= ~CAN_MCR_RFLM;
}
if (txfp) {
CAN_MCR(canport) |= CAN_MCR_TXFP;
} else {
CAN_MCR(canport) &= ~CAN_MCR_TXFP;
}
if (silent) {
CAN_BTR(canport) |= CAN_BTR_SILM;
} else {
CAN_BTR(canport) &= ~CAN_BTR_SILM;
}
if (loopback) {
CAN_BTR(canport) |= CAN_BTR_LBKM;
} else {
CAN_BTR(canport) &= ~CAN_BTR_LBKM;
}
/* Set bit timings. */
CAN_BTR(canport) |= sjw | ts2 | ts1 |
((brp - 1ul) & CAN_BTR_BRP_MASK);
/* Request initialization "leave". */
CAN_MCR(canport) &= ~CAN_MCR_INRQ;
/* Wait for acknowledge. */
wait_ack = CAN_MSR_INAK_TIMEOUT;
while ((--wait_ack) &&
((CAN_MSR(canport) & CAN_MSR_INAK) == CAN_MSR_INAK));
if ((CAN_MSR(canport) & CAN_MSR_INAK) == CAN_MSR_INAK) {
ret = 1;
}
return ret;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Filter Init
Initialize incoming message filter and assign to FIFO.
@param[in] nr Unsigned int32. ID number of the filter.
@param[in] scale_32bit true for single 32bit, false for dual 16bit
@param[in] id_list_mode true for id lists, false for id/mask
@param[in] fr1 Unsigned int32. First filter register content.
@param[in] fr2 Unsigned int32. Second filter register content.
@param[in] fifo Unsigned int32. FIFO id.
@param[in] enable bool. Enable filter?
*/
void can_filter_init(uint32_t nr, bool scale_32bit,
bool id_list_mode, uint32_t fr1, uint32_t fr2,
uint32_t fifo, bool enable)
{
uint32_t filter_select_bit = 0x00000001 << nr;
/* Request initialization "enter". */
CAN_FMR(CAN1) |= CAN_FMR_FINIT;
/* Deactivate the filter. */
CAN_FA1R(CAN1) &= ~filter_select_bit;
if (scale_32bit) {
/* Set 32-bit scale for the filter. */
CAN_FS1R(CAN1) |= filter_select_bit;
} else {
/* Set 16-bit scale for the filter. */
CAN_FS1R(CAN1) &= ~filter_select_bit;
}
if (id_list_mode) {
/* Set filter mode to ID list mode. */
CAN_FM1R(CAN1) |= filter_select_bit;
} else {
/* Set filter mode to id/mask mode. */
CAN_FM1R(CAN1) &= ~filter_select_bit;
}
/* Set the first filter register. */
CAN_FiR1(CAN1, nr) = fr1;
/* Set the second filter register. */
CAN_FiR2(CAN1, nr) = fr2;
/* Select FIFO0 or FIFO1 as filter assignement. */
if (fifo) {
CAN_FFA1R(CAN1) |= filter_select_bit; /* FIFO1 */
} else {
CAN_FFA1R(CAN1) &= ~filter_select_bit; /* FIFO0 */
}
if (enable) {
CAN_FA1R(CAN1) |= filter_select_bit; /* Activate filter. */
}
/* Request initialization "leave". */
CAN_FMR(CAN1) &= ~CAN_FMR_FINIT;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Initialize a 16bit Message ID Mask Filter
@param[in] nr Unsigned int32. ID number of the filter.
@param[in] id1 Unsigned int16. First message ID to filter.
@param[in] mask1 Unsigned int16. First message ID bit mask.
@param[in] id2 Unsigned int16. Second message ID to filter.
@param[in] mask2 Unsigned int16. Second message ID bit mask.
@param[in] fifo Unsigned int32. FIFO id.
@param[in] enable bool. Enable filter?
*/
void can_filter_id_mask_16bit_init(uint32_t nr, uint16_t id1,
uint16_t mask1, uint16_t id2,
uint16_t mask2, uint32_t fifo, bool enable)
{
can_filter_init(nr, false, false,
((uint32_t)mask1 << 16) | (uint32_t)id1,
((uint32_t)mask2 << 16) | (uint32_t)id2, fifo, enable);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Initialize a 32bit Message ID Mask Filter
@param[in] nr Unsigned int32. ID number of the filter.
@param[in] id Unsigned int32. Message ID to filter.
@param[in] mask Unsigned int32. Message ID bit mask.
@param[in] fifo Unsigned int32. FIFO id.
@param[in] enable bool. Enable filter?
*/
void can_filter_id_mask_32bit_init(uint32_t nr, uint32_t id,
uint32_t mask, uint32_t fifo, bool enable)
{
can_filter_init(nr, true, false, id, mask, fifo, enable);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Initialize a 16bit Message ID List Filter
@param[in] nr Unsigned int32. ID number of the filter.
@param[in] id1 Unsigned int16. First message ID to match.
@param[in] id2 Unsigned int16. Second message ID to match.
@param[in] id3 Unsigned int16. Third message ID to match.
@param[in] id4 Unsigned int16. Fourth message ID to match.
@param[in] fifo Unsigned int32. FIFO id.
@param[in] enable bool. Enable filter?
*/
void can_filter_id_list_16bit_init(uint32_t nr,
uint16_t id1, uint16_t id2,
uint16_t id3, uint16_t id4,
uint32_t fifo, bool enable)
{
can_filter_init(nr, false, true,
((uint32_t)id1 << 16) | (uint32_t)id2,
((uint32_t)id3 << 16) | (uint32_t)id4, fifo, enable);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Initialize a 32bit Message ID List Filter
@param[in] nr Unsigned int32. ID number of the filter.
@param[in] id1 Unsigned int32. First message ID to match.
@param[in] id2 Unsigned int32. Second message ID to match.
@param[in] fifo Unsigned int32. FIFO id.
@param[in] enable bool. Enable filter?
*/
void can_filter_id_list_32bit_init(uint32_t nr,
uint32_t id1, uint32_t id2,
uint32_t fifo, bool enable)
{
can_filter_init(nr, true, true, id1, id2, fifo, enable);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Enable IRQ
@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
@param[in] irq Unsigned int32. IRQ bit(s).
*/
void can_enable_irq(uint32_t canport, uint32_t irq)
{
CAN_IER(canport) |= irq;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Disable IRQ
@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
@param[in] irq Unsigned int32. IRQ bit(s).
*/
void can_disable_irq(uint32_t canport, uint32_t irq)
{
CAN_IER(canport) &= ~irq;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Transmit Message
@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
@param[in] id Unsigned int32. Message ID.
@param[in] ext bool. Extended message ID?
@param[in] rtr bool. Request transmit?
@param[in] length Unsigned int8. Message payload length.
@param[in] data Unsigned int8[]. Message payload data.
@returns int 0, 1 or 2 on success and depending on which outgoing mailbox got
selected. -1 if no mailbox was available and no transmission got queued.
*/
int can_transmit(uint32_t canport, uint32_t id, bool ext, bool rtr,
uint8_t length, uint8_t *data)
{
int ret = 0;
uint32_t mailbox = 0;
union {
uint8_t data8[4];
uint32_t data32;
} tdlxr, tdhxr;
/* Check which transmit mailbox is empty if any. */
if ((CAN_TSR(canport) & CAN_TSR_TME0) == CAN_TSR_TME0) {
ret = 0;
mailbox = CAN_MBOX0;
} else if ((CAN_TSR(canport) & CAN_TSR_TME1) == CAN_TSR_TME1) {
ret = 1;
mailbox = CAN_MBOX1;
} else if ((CAN_TSR(canport) & CAN_TSR_TME2) == CAN_TSR_TME2) {
ret = 2;
mailbox = CAN_MBOX2;
} else {
ret = -1;
}
/* If we have no empty mailbox return with an error. */
if (ret == -1) {
return ret;
}
if (ext) {
/* Set extended ID. */
CAN_TIxR(canport, mailbox) = (id << CAN_TIxR_EXID_SHIFT) |
CAN_TIxR_IDE;
} else {
/* Set standard ID. */
CAN_TIxR(canport, mailbox) = id << CAN_TIxR_STID_SHIFT;
}
/* Set/clear remote transmission request bit. */
if (rtr) {
CAN_TIxR(canport, mailbox) |= CAN_TIxR_RTR; /* Set */
}
/* Set the DLC. */
CAN_TDTxR(canport, mailbox) &= ~CAN_TDTxR_DLC_MASK;
CAN_TDTxR(canport, mailbox) |= (length & CAN_TDTxR_DLC_MASK);
switch (length) {
case 8:
tdhxr.data8[3] = data[7];
/* fall through */
case 7:
tdhxr.data8[2] = data[6];
/* fall through */
case 6:
tdhxr.data8[1] = data[5];
/* fall through */
case 5:
tdhxr.data8[0] = data[4];
/* fall through */
case 4:
tdlxr.data8[3] = data[3];
/* fall through */
case 3:
tdlxr.data8[2] = data[2];
/* fall through */
case 2:
tdlxr.data8[1] = data[1];
/* fall through */
case 1:
tdlxr.data8[0] = data[0];
/* fall through */
default:
break;
}
/* Set the data. */
CAN_TDLxR(canport, mailbox) = tdlxr.data32;
CAN_TDHxR(canport, mailbox) = tdhxr.data32;
/* Request transmission. */
CAN_TIxR(canport, mailbox) |= CAN_TIxR_TXRQ;
return ret;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Release FIFO
@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
@param[in] fifo Unsigned int8. FIFO id.
*/
void can_fifo_release(uint32_t canport, uint8_t fifo)
{
if (fifo == 0) {
CAN_RF0R(canport) |= CAN_RF1R_RFOM1;
} else {
CAN_RF1R(canport) |= CAN_RF1R_RFOM1;
}
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Receive Message
@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
@param[in] fifo Unsigned int8. FIFO id.
@param[in] release bool. Release the FIFO automatically after coping data out.
@param[out] id Unsigned int32 pointer. Message ID.
@param[out] ext bool pointer. The message ID is extended?
@param[out] rtr bool pointer. Request of transmission?
@param[out] fmi Unsigned int8 pointer. ID of the matched filter.
@param[out] length Unsigned int8 pointer. Length of message payload.
@param[out] data Unsigned int8[]. Message payload data.
@param[out] timestamp Pointer to store the message timestamp.
Only valid on time triggered CAN. Use NULL to ignore.
*/
void can_receive(uint32_t canport, uint8_t fifo, bool release, uint32_t *id,
bool *ext, bool *rtr, uint8_t *fmi, uint8_t *length,
uint8_t *data, uint16_t *timestamp)
{
uint32_t fifo_id = 0;
union {
uint8_t data8[4];
uint32_t data32;
} rdlxr, rdhxr;
const uint32_t fifoid_array[2] = {CAN_FIFO0, CAN_FIFO1};
fifo_id = fifoid_array[fifo];
/* Get type of CAN ID and CAN ID. */
if (CAN_RIxR(canport, fifo_id) & CAN_RIxR_IDE) {
*ext = true;
/* Get extended CAN ID. */
*id = (CAN_RIxR(canport, fifo_id) >> CAN_RIxR_EXID_SHIFT) &
CAN_RIxR_EXID_MASK;
} else {
*ext = false;
/* Get standard CAN ID. */
*id = (CAN_RIxR(canport, fifo_id) >> CAN_RIxR_STID_SHIFT) &
CAN_RIxR_STID_MASK;
}
/* Get remote transmit flag. */
if (CAN_RIxR(canport, fifo_id) & CAN_RIxR_RTR) {
*rtr = true;
} else {
*rtr = false;
}
/* Get filter match ID. */
*fmi = ((CAN_RDTxR(canport, fifo_id) & CAN_RDTxR_FMI_MASK) >>
CAN_RDTxR_FMI_SHIFT);
/* Get data length. */
*length = CAN_RDTxR(canport, fifo_id) & CAN_RDTxR_DLC_MASK;
/* accelerate reception by copying the CAN data from the controller
* memory to the fast internal RAM
*/
if (timestamp) {
*timestamp = (CAN_RDTxR(canport, fifo_id) &
CAN_RDTxR_TIME_MASK) >> CAN_RDTxR_TIME_SHIFT;
}
rdlxr.data32 = CAN_RDLxR(canport, fifo_id);
rdhxr.data32 = CAN_RDHxR(canport, fifo_id);
/* */
/* Get data.
* Byte wise copy is needed because we do not know the alignment
* of the input buffer.
* Here copying 8 bytes unconditionally is faster than using loop
*
* It is OK to copy all 8 bytes because the upper layer must be
* prepared for data length bigger expected.
* In contrary the driver has no information about the intended size.
* This could be different if the max length would be handed over
* to the function, but it is not the case
*/
data[0] = rdlxr.data8[0];
data[1] = rdlxr.data8[1];
data[2] = rdlxr.data8[2];
data[3] = rdlxr.data8[3];
data[4] = rdhxr.data8[0];
data[5] = rdhxr.data8[1];
data[6] = rdhxr.data8[2];
data[7] = rdhxr.data8[3];
/* Release the FIFO. */
if (release) {
can_fifo_release(canport, fifo);
}
}
bool can_available_mailbox(uint32_t canport)
{
return CAN_TSR(canport) & (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2);
}

View File

@@ -0,0 +1,124 @@
/** @addtogroup adc_file ADC peripheral API
@ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2012
Ken Sarkies <ksarkies@internode.on.net>
@date 30 August 2012
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/adc.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @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
* NOTE Common with f1, f2 and f37x
*/
void adc_set_sample_time(uint32_t adc, uint8_t channel, uint8_t time)
{
uint32_t reg32;
if (channel < 10) {
reg32 = ADC_SMPR2(adc);
reg32 &= ~(0x7 << (channel * 3));
reg32 |= (time << (channel * 3));
ADC_SMPR2(adc) = reg32;
} else {
reg32 = ADC_SMPR1(adc);
reg32 &= ~(0x7 << ((channel - 10) * 3));
reg32 |= (time << ((channel - 10) * 3));
ADC_SMPR1(adc) = reg32;
}
}
/*---------------------------------------------------------------------------*/
/** @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
* NOTE Common with f1, f2 and f37x
*/
void adc_set_sample_time_on_all_channels(uint32_t adc, uint8_t time)
{
uint8_t i;
uint32_t reg32 = 0;
for (i = 0; i <= 9; i++) {
reg32 |= (time << (i * 3));
}
ADC_SMPR2(adc) = reg32;
for (i = 10; i <= 17; i++) {
reg32 |= (time << ((i - 10) * 3));
}
ADC_SMPR1(adc) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set Dual/Triple Mode
The multiple mode uses ADC1 as master, ADC2 and optionally ADC3 in a slave
arrangement. This setting is applied to ADC1 only.
The various modes possible are described in the reference manual.
@param[in] mode Unsigned int32. Multiple mode selection from @ref adc_multi_mode
*/
void adc_set_multi_mode(uint32_t mode)
{
ADC_CCR |= mode;
}
/** Enable The VBat Sensor.
* This enables the battery voltage measurements on ADC1 channel 18. On
* STM32F42x and STM32F43x, this must be disabled when the temperature sensor
* is enabled. If both are enabled, only the VBat conversion is performed.
*/
void adc_enable_vbat_sensor(void)
{
ADC_CCR |= ADC_CCR_VBATE;
}
/** Disable The VBat Sensor.
* Disabling this will reduce power consumption from the battery voltage
* measurement.
*/
void adc_disable_vbat_sensor(void)
{
ADC_CCR &= ~ADC_CCR_VBATE;
}
/**@}*/

View File

@@ -0,0 +1,779 @@
/** @addtogroup adc_file ADC peripheral API
@ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly
2009 Edward Cheeseman <evbuilder@users.sourceforge.net>
@author @htmlonly &copy; @endhtmlonly
2012 Ken Sarkies <ksarkies@internode.on.net>
@author @htmlonly &copy; @endhtmlonly
2014 Karl Palsson <karlp@tweak.net.au>
This library supports one style of the Analog to Digital Conversion System in
the STM32 series of ARM Cortex Microcontrollers by ST Microelectronics.
The style of ADC Peripheral supported by this code is found in the F1, F2,
F37x, F38x, F4, and L1 series devices (at the time of writing) but is quite
different to the style found on the F0 and F30x and F31x.
Devices can have up to three A/D converters each with their own set of
registers.
However all the A/D converters share a common clock. On most devices, this is
prescaled from the APB2 clock by default by a minimum factor of 2 to a maximum
of 8, though on the L1 this is always a divider from the HSI. (And therefore HSI
_must_ be enabled before attempting to enable the ADC)
Each A/D converter has up to ADC_MAX_CHANNELS channels:
@li On ADC1 the analog channels 16 and 17 are internally connected to the
temperature sensor and V<sub>REFINT</sub>, respectively.
@li On ADC2 (if available) the analog channels 16 and 17 are internally
connected to V<sub>SS</sub>.
@li On ADC3 (if available) the analog channels 9, 14, 15, 16 and 17 are
internally connected to V<sub>SS</sub>.
The conversions can occur as a one-off conversion whereby the process stops once
conversion is complete. The conversions can also be continuous wherein a new
conversion starts immediately the previous conversion has ended.
Conversion can occur as a single channel conversion or a scan of a group of
channels in either continuous or one-off mode. If more than one channel is
converted in a scan group, DMA must be used to transfer the data as there is
only one result register available. An interrupt can be set to occur at the end
of conversion, which occurs after all channels have been scanned.
A discontinuous mode allows a subgroup of group of a channels to be converted in
bursts of a given length.
Injected conversions allow a second group of channels to be converted separately
from the regular group. An interrupt can be set to occur at the end of
conversion, which occurs after all channels have been scanned.
@section adc_api_ex Basic ADC Handling API.
Example 1: Simple single channel conversion polled. Enable the peripheral clock
and ADC, reset ADC and set the prescaler divider. Set dual mode to independent
(default). Enable triggering for a software trigger.
@code
rcc_periph_clock_enable(RCC_ADC1);
adc_power_off(ADC1);
rcc_periph_reset_pulse(RST_ADC1);
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_enable_trigger(ADC1, ADC_CR2_EXTSEL_SWSTART);
adc_power_on(ADC1);
adc_reset_calibration(ADC1);
adc_calibration(ADC1);
adc_start_conversion_regular(ADC1);
while (! adc_eoc(ADC1));
reg16 = adc_read_regular(ADC1);
@endcode
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2014 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/adc.h>
/*---------------------------------------------------------------------------*/
/** @brief ADC Off
Turn off the ADC to reduce power consumption to a few microamps.
@param[in] adc Unsigned int32. ADC block register address base @ref
adc_reg_base.
*/
void adc_power_off(uint32_t adc)
{
ADC_CR2(adc) &= ~ADC_CR2_ADON;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog for Regular Conversions
The analog watchdog allows the monitoring of an analog signal between two
threshold levels. The thresholds must be preset.
@param[in] adc Unsigned int32. ADC block register address base @ref
adc_reg_base.
*/
void adc_enable_analog_watchdog_regular(uint32_t adc)
{
ADC_CR1(adc) |= ADC_CR1_AWDEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Analog Watchdog for Regular Conversions
@param[in] adc Unsigned int32. ADC block register address base @ref
adc_reg_base.
*/
void adc_disable_analog_watchdog_regular(uint32_t adc)
{
ADC_CR1(adc) &= ~ADC_CR1_AWDEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog for Injected Conversions
The analog watchdog allows the monitoring of an analog signal between two
threshold levels. The thresholds must be preset. Comparison is done before data
alignment takes place, so the thresholds are left-aligned.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_analog_watchdog_injected(uint32_t adc)
{
ADC_CR1(adc) |= ADC_CR1_JAWDEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Analog Watchdog for Injected Conversions
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_analog_watchdog_injected(uint32_t adc)
{
ADC_CR1(adc) &= ~ADC_CR1_JAWDEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Discontinuous Mode for Regular Conversions
In this mode the ADC converts, on each trigger, a subgroup of up to 8 of the
defined regular channel group. The subgroup is defined by the number of
consecutive channels to be converted. After a subgroup has been converted
the next trigger will start conversion of the immediately following subgroup
of the same length or until the whole group has all been converted. When the
the whole group has been converted, the next trigger will restart conversion
of the subgroup at the beginning of the whole group.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] length Unsigned int8. Number of channels in the group @ref
adc_cr1_discnum
*/
void adc_enable_discontinuous_mode_regular(uint32_t adc, uint8_t length)
{
if ((length-1) > 7) {
return;
}
ADC_CR1(adc) |= ADC_CR1_DISCEN;
ADC_CR1(adc) |= ((length-1) << ADC_CR1_DISCNUM_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Discontinuous Mode for Regular Conversions
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_discontinuous_mode_regular(uint32_t adc)
{
ADC_CR1(adc) &= ~ADC_CR1_DISCEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Discontinuous Mode for Injected Conversions
In this mode the ADC converts sequentially one channel of the defined group of
injected channels, cycling back to the first channel in the group once the
entire group has been converted.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_discontinuous_mode_injected(uint32_t adc)
{
ADC_CR1(adc) |= ADC_CR1_JDISCEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Discontinuous Mode for Injected Conversions
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_discontinuous_mode_injected(uint32_t adc)
{
ADC_CR1(adc) &= ~ADC_CR1_JDISCEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Automatic Injected Conversions
The ADC converts a defined injected group of channels immediately after the
regular channels have been converted. The external trigger on the injected
channels is disabled as required.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_automatic_injected_group_conversion(uint32_t adc)
{
adc_disable_external_trigger_injected(adc);
ADC_CR1(adc) |= ADC_CR1_JAUTO;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Automatic Injected Conversions
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_automatic_injected_group_conversion(uint32_t adc)
{
ADC_CR1(adc) &= ~ADC_CR1_JAUTO;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog for All Regular and/or Injected Channels
The analog watchdog allows the monitoring of an analog signal between two
threshold levels. The thresholds must be preset. Comparison is done before data
alignment takes place, so the thresholds are left-aligned.
@note The analog watchdog must be enabled for either or both of the regular or
injected channels. If neither are enabled, the analog watchdog feature will be
disabled.
@ref adc_enable_analog_watchdog_injected, @ref
adc_enable_analog_watchdog_regular.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_analog_watchdog_on_all_channels(uint32_t adc)
{
ADC_CR1(adc) &= ~ADC_CR1_AWDSGL;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog for a Selected Channel
The analog watchdog allows the monitoring of an analog signal between two
threshold levels. The thresholds must be preset. Comparison is done before data
alignment takes place, so the thresholds are left-aligned.
@note The analog watchdog must be enabled for either or both of the regular or
injected channels. If neither are enabled, the analog watchdog feature will be
disabled. If both are enabled, the same channel number is monitored.
@ref adc_enable_analog_watchdog_injected, @ref
adc_enable_analog_watchdog_regular.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] channel Unsigned int8. ADC channel number @ref adc_watchdog_channel
*/
void adc_enable_analog_watchdog_on_selected_channel(uint32_t adc,
uint8_t channel)
{
uint32_t reg32;
reg32 = (ADC_CR1(adc) & ~ADC_CR1_AWDCH_MASK); /* Clear bits [4:0]. */
if (channel <= ADC_CR1_AWDCH_MAX) {
reg32 |= channel;
}
ADC_CR1(adc) = reg32;
ADC_CR1(adc) |= ADC_CR1_AWDSGL;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set Scan Mode
In this mode a conversion consists of a scan of the predefined set of channels,
regular and injected, each channel conversion immediately following the
previous one. It can use single, continuous or discontinuous mode.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_scan_mode(uint32_t adc)
{
ADC_CR1(adc) |= ADC_CR1_SCAN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Scan Mode
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_scan_mode(uint32_t adc)
{
ADC_CR1(adc) &= ~ADC_CR1_SCAN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Injected End-Of-Conversion Interrupt
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_eoc_interrupt_injected(uint32_t adc)
{
ADC_CR1(adc) |= ADC_CR1_JEOCIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Injected End-Of-Conversion Interrupt
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_eoc_interrupt_injected(uint32_t adc)
{
ADC_CR1(adc) &= ~ADC_CR1_JEOCIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog Interrupt
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_awd_interrupt(uint32_t adc)
{
ADC_CR1(adc) |= ADC_CR1_AWDIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Analog Watchdog Interrupt
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_awd_interrupt(uint32_t adc)
{
ADC_CR1(adc) &= ~ADC_CR1_AWDIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Regular End-Of-Conversion Interrupt
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_eoc_interrupt(uint32_t adc)
{
ADC_CR1(adc) |= ADC_CR1_EOCIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Regular End-Of-Conversion Interrupt
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_eoc_interrupt(uint32_t adc)
{
ADC_CR1(adc) &= ~ADC_CR1_EOCIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set the Data as Left Aligned
@param[in] adc Unsigned int32. ADC block register address base @ref
adc_reg_base.
*/
void adc_set_left_aligned(uint32_t adc)
{
ADC_CR2(adc) |= ADC_CR2_ALIGN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set the Data as Right Aligned
@param[in] adc Unsigned int32. ADC block register address base @ref
adc_reg_base.
*/
void adc_set_right_aligned(uint32_t adc)
{
ADC_CR2(adc) &= ~ADC_CR2_ALIGN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read the End-of-Conversion Flag
This flag is set after all channels of a regular or injected group have been
converted.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@returns bool. End of conversion flag.
*/
bool adc_eoc(uint32_t adc)
{
return (ADC_SR(adc) & ADC_SR_EOC) != 0;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read the End-of-Conversion Flag for Injected Conversion
This flag is set after all channels of an injected group have been converted.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@returns bool. End of conversion flag.
*/
bool adc_eoc_injected(uint32_t adc)
{
return (ADC_SR(adc) & ADC_SR_JEOC) != 0;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read from the Regular Conversion Result Register
The result read back is 12 bits, right or left aligned within the first 16 bits.
For ADC1 only, the higher 16 bits will hold the result from ADC2 if
an appropriate dual mode has been set @see adc_set_dual_mode.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@returns Unsigned int32 conversion result.
*/
uint32_t adc_read_regular(uint32_t adc)
{
return ADC_DR(adc);
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read from an Injected Conversion Result Register
The result read back from the selected injected result register (one of four)
is 12 bits, right or left aligned within the first 16 bits. The result can have
a negative value if the injected channel offset has been set @see
adc_set_injected_offset.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] reg Unsigned int8. Register number (1 ... 4).
@returns Unsigned int32 conversion result.
*/
uint32_t adc_read_injected(uint32_t adc, uint8_t reg)
{
switch (reg) {
case 1:
return ADC_JDR1(adc);
case 2:
return ADC_JDR2(adc);
case 3:
return ADC_JDR3(adc);
case 4:
return ADC_JDR4(adc);
}
return 0;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Continuous Conversion Mode
In this mode the ADC starts a new conversion of a single channel or a channel
group immediately following completion of the previous channel group conversion.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_set_continuous_conversion_mode(uint32_t adc)
{
ADC_CR2(adc) |= ADC_CR2_CONT;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Single Conversion Mode
In this mode the ADC performs a conversion of one channel or a channel group
and stops.
@param[in] adc Unsigned int32. ADC block register address base @ref
adc_reg_base.
*/
void adc_set_single_conversion_mode(uint32_t adc)
{
ADC_CR2(adc) &= ~ADC_CR2_CONT;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set Analog Watchdog Upper Threshold
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] threshold Upper threshold value, 12bit right aligned.
*/
void adc_set_watchdog_high_threshold(uint32_t adc, uint16_t threshold)
{
uint32_t reg32 = 0;
reg32 = (uint32_t)threshold;
reg32 &= ADC_HT_MSK;
ADC_HTR(adc) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set Analog Watchdog Lower Threshold
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] threshold Lower threshold value, 12bit right aligned.
*/
void adc_set_watchdog_low_threshold(uint32_t adc, uint16_t threshold)
{
uint32_t reg32 = 0;
reg32 = (uint32_t)threshold;
reg32 &= ADC_LT_MSK;
ADC_LTR(adc) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set a Regular Channel Conversion Sequence
Define a sequence of channels to be converted as a regular group with a length
from 1 to ADC_REGULAR_SEQUENCE_MAX channels. If this is called during
conversion, the current conversion is reset and conversion begins again with
the newly defined group.
@param[in] adc Unsigned int32. ADC block base address @ref adc_reg_base.
@param[in] length Unsigned int8. Number of channels in the group.
@param[in] channel Unsigned int8[]. Set of channels in sequence, integers 0..31.
*/
void adc_set_regular_sequence(uint32_t adc, uint8_t length, uint8_t channel[])
{
uint32_t fifth6 = 0;
uint32_t fourth6 = 0;
uint32_t third6 = 0;
uint32_t second6 = 0;
uint32_t first6 = 0;
uint8_t i = 0;
if (length > ADC_SQR_MAX_CHANNELS_REGULAR) {
return;
}
for (i = 1; i <= length; i++) {
if (i <= 6) {
first6 |= (channel[i - 1] << ((i - 1) * 5));
}
if ((i > 6) && (i <= 12)) {
second6 |= (channel[i - 1] << ((i - 6 - 1) * 5));
}
if ((i > 12) && (i <= 18)) {
third6 |= (channel[i - 1] << ((i - 12 - 1) * 5));
}
if ((i > 18) && (i <= 24)) {
fourth6 |= (channel[i - 1] << ((i - 18 - 1) * 5));
}
if ((i > 24) && (i <= 28)) {
fifth6 |= (channel[i - 1] << ((i - 24 - 1) * 5));
}
}
#if defined(ADC_SQR5)
ADC_SQR1(adc) = fifth6 | ((length - 1) << ADC_SQR1_L_LSB);
ADC_SQR2(adc) = fourth6;
ADC_SQR3(adc) = third6;
ADC_SQR4(adc) = second6;
ADC_SQR5(adc) = first6;
#else
ADC_SQR1(adc) = third6 | ((length - 1) << ADC_SQR1_L_LSB);
ADC_SQR2(adc) = second6;
ADC_SQR3(adc) = first6;
#endif
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set an Injected Channel Conversion Sequence
Defines a sequence of channels to be converted as an injected group with a
length from 1 to 4 channels. If this is called during conversion, the current
conversion is reset and conversion begins again with the newly defined group.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] length Unsigned int8. Number of channels in the group.
@param[in] channel Unsigned int8[]. Set of channels in sequence, integers 0..18
*/
void adc_set_injected_sequence(uint32_t adc, uint8_t length, uint8_t channel[])
{
uint32_t reg32 = 0;
uint8_t i = 0;
/* Maximum sequence length is 4 channels. Minimum sequence is 1.*/
if ((length - 1) > 3) {
return;
}
for (i = 0; i < length; i++) {
reg32 |= ADC_JSQR_JSQ_VAL(4 - i, channel[length - i - 1]);
}
reg32 |= ADC_JSQR_JL_VAL(length);
ADC_JSQR(adc) = reg32;
}
/*----------------------------------------------------------------------------*/
/** @brief ADC Set the Injected Channel Data Offset
This value is subtracted from the injected channel results after conversion is
complete, and can result in negative results. A separate value can be specified
for each injected data register.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] reg Unsigned int8. Register number (1 ... 4).
@param[in] offset Unsigned int32.
*/
void adc_set_injected_offset(uint32_t adc, uint8_t reg, uint32_t offset)
{
switch (reg) {
case 1:
ADC_JOFR1(adc) = offset;
break;
case 2:
ADC_JOFR2(adc) = offset;
break;
case 3:
ADC_JOFR3(adc) = offset;
break;
case 4:
ADC_JOFR4(adc) = offset;
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Software Triggered Conversion on Regular Channels
This starts conversion on a set of defined regular channels if the ADC trigger
is set to be a software trigger. It is cleared by hardware once conversion
starts.
Special F1 Note this is a software trigger and requires triggering to be
enabled and the trigger source to be set appropriately otherwise conversion
will not start. This is not the same as the ADC start conversion operation.
@param[in] adc Unsigned int32. ADC block register address base @ref
adc_reg_base.
*/
void adc_start_conversion_regular(uint32_t adc)
{
/* Start conversion on regular channels. */
ADC_CR2(adc) |= ADC_CR2_SWSTART;
/* Wait until the ADC starts the conversion. */
while (ADC_CR2(adc) & ADC_CR2_SWSTART);
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Software Triggered Conversion on Injected Channels
This starts conversion on a set of defined injected channels if the ADC trigger
is set to be a software trigger. It is cleared by hardware once conversion
starts.
Special F1 Note this is a software trigger and requires triggering to be
enabled and the trigger source to be set appropriately otherwise conversion
will not start. This is not the same as the ADC start conversion operation.
@param[in] adc Unsigned int32. ADC block register address base @ref
adc_reg_base.
*/
void adc_start_conversion_injected(uint32_t adc)
{
/* Start conversion on injected channels. */
ADC_CR2(adc) |= ADC_CR2_JSWSTART;
/* Wait until the ADC starts the conversion. */
while (ADC_CR2(adc) & ADC_CR2_JSWSTART);
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable DMA Transfers
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_dma(uint32_t adc)
{
ADC_CR2(adc) |= ADC_CR2_DMA;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable DMA Transfers
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_dma(uint32_t adc)
{
ADC_CR2(adc) &= ~ADC_CR2_DMA;
}
/*---------------------------------------------------------------------------*/
/** @brief Read a Status Flag.
@param[in] adc Unsigned int32. ADC register address base @ref adc_reg_base
@param[in] flag Unsigned int32. Status register flag @ref adc_sr_values.
@returns boolean: flag set.
*/
bool adc_get_flag(uint32_t adc, uint32_t flag)
{
return ADC_SR(adc) & flag;
}
/*---------------------------------------------------------------------------*/
/** @brief Clear a Status Flag.
@param[in] adc Unsigned int32. ADC register address base @ref adc_reg_base
@param[in] flag Unsigned int32. Status register flag @ref adc_sr_values.
*/
void adc_clear_flag(uint32_t adc, uint32_t flag)
{
/* All defined bits are 'r' or 'rc_w0' */
ADC_SR(adc) = ~flag;
}
/*---------------------------------------------------------------------------*/
/**@}*/

View File

@@ -0,0 +1,360 @@
/** @addtogroup adc_file ADC peripheral API
@ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2012
Ken Sarkies <ksarkies@internode.on.net>
@date 30 August 2012
This library supports the A/D Converter Control System in the STM32 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. The ADC resolution can be set to 12, 10, 8 or 6 bits.
Each A/D converter has multiple channels, not all of which might be available
externally. Internal channels can be used for the the temperature sensor,
VBat monitoring, and the internal reference voltage VREFINT. Consult the
Reference manual for the specifics of your part.
@sa ADC_MAX_CHANNELS
@sa ADC_CHANNEL_TEMP
@sa ADC_CHANNEL_VREF
@sa ADC_CHANNEL_VBAT
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 the sample time to a
minimum of 3 cycles. Set multiple mode to independent.
@code
gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1);
rcc_periph_clock_enable(RCC_ADC1);
adc_set_clk_prescale(ADC_CCR_ADCPRE_BY2);
adc_disable_scan_mode(ADC1);
adc_set_single_conversion_mode(ADC1);
adc_set_sample_time(ADC1, ADC_CHANNEL0, ADC_SMPR_SMP_3CYC);
uint8_t channels[] = ADC_CHANNEL0;
adc_set_regular_sequence(ADC1, 1, channels);
adc_set_multi_mode(ADC_CCR_MULTI_INDEPENDENT);
adc_power_on(ADC1);
adc_start_conversion_regular(ADC1);
while (!adc_eoc(ADC1));
reg16 = adc_read_regular(ADC1);
@endcode
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 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/adc.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @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 have no effect.
* NOTE Common with L1 and F2
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_power_on(uint32_t adc)
{
ADC_CR2(adc) |= ADC_CR2_ADON;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set Clock Prescale
The ADC clock can be prescaled.
The Clock sources and scaler values are part specific.
@param[in] prescale Prescale value for ADC Clock @ref adc_ccr_adcpre
*/
void adc_set_clk_prescale(uint32_t prescale)
{
uint32_t reg32 = ((ADC_CCR & ~ADC_CCR_ADCPRE_MASK) | prescale);
ADC_CCR = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable an External Trigger for Regular Channels
This enables an external trigger for set of defined regular channels, and sets
the polarity of the trigger event: rising or falling edge or both. Note that if
the trigger polarity is zero, triggering is disabled.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] trigger Unsigned int32. Trigger identifier @ref adc_trigger_regular
@param[in] polarity Unsigned int32. Trigger polarity @ref
adc_trigger_polarity_regular
*/
void adc_enable_external_trigger_regular(uint32_t adc, uint32_t trigger,
uint32_t polarity)
{
uint32_t reg32 = ADC_CR2(adc);
reg32 &= ~(ADC_CR2_EXTSEL_MASK | ADC_CR2_EXTEN_MASK);
reg32 |= (trigger | polarity);
ADC_CR2(adc) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @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(uint32_t adc)
{
ADC_CR2(adc) &= ~ADC_CR2_EXTEN_MASK;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable an External Trigger for Injected Channels
This enables an external trigger for set of defined injected channels, and sets
the polarity of the trigger event: rising or falling edge or both.
@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
@param[in] polarity Unsigned int32. Trigger polarity @ref
adc_trigger_polarity_injected
*/
void adc_enable_external_trigger_injected(uint32_t adc, uint32_t trigger,
uint32_t polarity)
{
uint32_t reg32 = ADC_CR2(adc);
reg32 &= ~(ADC_CR2_JEXTSEL_MASK | ADC_CR2_JEXTEN_MASK);
reg32 |= (trigger | polarity);
ADC_CR2(adc) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @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(uint32_t adc)
{
ADC_CR2(adc) &= ~ADC_CR2_JEXTEN_MASK;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set Resolution
ADC Resolution can be reduced from 12 bits to 10, 8 or 6 bits for a
corresponding reduction in conversion time (resolution + 3 ADC clock cycles).
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@param[in] resolution Unsigned int32. Resolution value @ref adc_cr1_res
*/
void adc_set_resolution(uint32_t adc, uint32_t resolution)
{
uint32_t reg32 = ADC_CR1(adc);
reg32 &= ~ADC_CR1_RES_MASK;
reg32 |= resolution;
ADC_CR1(adc) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable the Overrun Interrupt
The overrun interrupt is generated when data is not read from a result register
before the next conversion is written. If DMA is enabled, all transfers are
terminated and any conversion sequence is aborted.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_enable_overrun_interrupt(uint32_t adc)
{
ADC_CR1(adc) |= ADC_CR1_OVRIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable the Overrun Interrupt
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_disable_overrun_interrupt(uint32_t adc)
{
ADC_CR1(adc) &= ~ADC_CR1_OVRIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read the Overrun Flag
The overrun flag is set when data is not read from a result register before the
next conversion is written. If DMA is enabled, all transfers are terminated and
any conversion sequence is aborted.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@returns Unsigned int32 conversion result.
*/
bool adc_get_overrun_flag(uint32_t adc)
{
return ADC_SR(adc) & ADC_SR_OVR;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Clear Overrun Flags
The overrun flag is cleared. Note that if an overrun occurs, DMA is terminated.
The flag must be cleared and the DMA stream and ADC reinitialised to resume
conversions (see the reference manual).
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@returns Unsigned int32 conversion result.
*/
void adc_clear_overrun_flag(uint32_t adc)
{
/* need to write zero to clear this */
ADC_SR(adc) &= ~ADC_SR_OVR;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable an EOC for Each Conversion
The EOC is set after each conversion in a sequence rather than at the end of the
sequence. Overrun detection is enabled only if DMA is enabled.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_eoc_after_each(uint32_t adc)
{
ADC_CR2(adc) |= ADC_CR2_EOCS;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable the EOC for Each Conversion
The EOC is set at the end of each sequence rather than after each conversion in
the sequence. Overrun detection is enabled always.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_eoc_after_group(uint32_t adc)
{
ADC_CR2(adc) &= ~ADC_CR2_EOCS;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set DMA to Continue
This must be set to allow DMA to continue to operate after the last conversion
in the DMA sequence. This allows DMA to be used in continuous circular mode.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_set_dma_continue(uint32_t adc)
{
ADC_CR2(adc) |= ADC_CR2_DDS;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set DMA to Terminate
This must be set to allow DMA to terminate after the last conversion in the DMA
sequence. This can avoid overrun errors.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_set_dma_terminate(uint32_t adc)
{
ADC_CR2(adc) &= ~ADC_CR2_DDS;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read the Analog Watchdog Flag
This flag is set when the converted voltage crosses the high or low thresholds.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
@returns bool. AWD flag.
*/
bool adc_awd(uint32_t adc)
{
return ADC_SR(adc) & ADC_SR_AWD;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable The Temperature Sensor
This enables both the sensor and the reference voltage measurements on ADC1.
On STM32F42x and STM32F43x, the temperature sensor is
connected to ADC1 channel 18, the same as VBat. If both are enabled, only the
VBat conversion is performed.
*/
void adc_enable_temperature_sensor(void)
{
ADC_CCR |= ADC_CCR_TSVREFE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable The Temperature Sensor
Disabling this will reduce power consumption from the sensor and the reference
voltage measurements.
*/
void adc_disable_temperature_sensor(void)
{
ADC_CCR &= ~ADC_CCR_TSVREFE;
}
/**@}*/

View File

@@ -0,0 +1,430 @@
/** @addtogroup adc_file ADC peripheral API
@ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly
2015 Karl Palsson <karlp@tweak.net.au>
This library supports one style of the Analog to Digital Conversion System in
the STM32 series of ARM Cortex Microcontrollers by ST Microelectronics.
The style of ADC Peripheral supported by this code is found in the F0, L0 and
F30x series devices (at the time of writing)
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/adc.h>
/** @brief ADC Read the End-of-Conversion Flag
*
* This flag is set by hardware at the end of each regular conversion of a
* channel when a new data is available in the ADCx_DR register.
*
* @param[in] adc Unsigned int32. ADC block register address base
* @ref adc_reg_base
* @returns bool. End of conversion flag.
*/
bool adc_eoc(uint32_t adc)
{
return ADC_ISR(adc) & ADC_ISR_EOC;
}
/** @brief ADC Read the End-of-Sequence Flag for Regular Conversions
*
* This flag is set after all channels of an regular group have been
* converted.
*
* @param[in] adc Unsigned int32. ADC block register address base
* @ref adc_reg_base
* @returns bool. End of conversion flag.
*/
bool adc_eos(uint32_t adc)
{
return ADC_ISR(adc) & ADC_ISR_EOS;
}
/**
* Turn on the ADC (async)
* @sa adc_wait_power_on
* @param adc ADC Block register address base @ref adc_reg_base
*/
void adc_power_on_async(uint32_t adc)
{
ADC_CR(adc) |= ADC_CR_ADEN;
}
/**
* Is the ADC powered up and ready?
* @sa adc_power_on_async
* @param adc ADC Block register address base @ref adc_reg_base
* @return true if adc is ready for use
*/
bool adc_is_power_on(uint32_t adc)
{
return ADC_ISR(adc) & ADC_ISR_ADRDY;
}
/**
* Turn on the ADC
* @sa adc_power_on_async
* @param adc ADC Block register address base @ref adc_reg_base
*/
void adc_power_on(uint32_t adc)
{
adc_power_on_async(adc);
while (!adc_is_power_on(adc));
}
/**
* Turn off the ADC (async)
* This will actually block if it needs to turn off a currently running
* conversion, as per ref man. (Handles injected on hardware that supports
* injected conversions.
* @sa adc_wait_power_off
* @param adc ADC Block register address base @ref adc_reg_base
*/
void adc_power_off_async(uint32_t adc)
{
if (adc_is_power_off(adc)) {
return;
}
uint32_t checks = ADC_CR_ADSTART;
uint32_t stops = ADC_CR_ADSTP;
#if defined(ADC_CR_JADSTART)
checks |= ADC_CR_JADSTART;
stops |= ADC_CR_JADSTP;
#endif
if (ADC_CR(adc) & checks) {
ADC_CR(adc) |= stops;
while (ADC_CR(adc) & checks);
}
ADC_CR(adc) |= ADC_CR_ADDIS;
}
/**
* Is the ADC powered down?
* @sa adc_power_off_async
* @param adc ADC Block register address base @ref adc_reg_base
*/
bool adc_is_power_off(uint32_t adc)
{
return !(ADC_CR(adc) & ADC_CR_ADEN);
}
/**
* Turn off the ADC
* This will actually block if it needs to turn off a currently running
* conversion, as per ref man.
* @sa adc_power_off_async
* @param adc ADC Block register address base @ref adc_reg_base
*/
void adc_power_off(uint32_t adc)
{
adc_power_off_async(adc);
while (!adc_is_power_off(adc));
}
/**
* Start the ADC calibration and immediately return.
* @sa adc_calibrate
* @sa adc_is_calibrating
* @param adc ADC Block register address base @ref adc_reg_base
*/
void adc_calibrate_async(uint32_t adc)
{
ADC_CR(adc) |= ADC_CR_ADCAL;
}
/**
* Is the ADC Calibrating?
* @param adc ADC Block register address base @ref adc_reg_base
* @return true if the adc is currently calibrating
*/
bool adc_is_calibrating(uint32_t adc)
{
return ADC_CR(adc) & ADC_CR_ADCAL;
}
/**
* Start ADC calibration and wait for it to finish
* @param adc ADC Block register address base @ref adc_reg_base
*/
void adc_calibrate(uint32_t adc)
{
adc_calibrate_async(adc);
while (adc_is_calibrating(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 ADC block register address base @ref adc_reg_base
*/
void adc_set_continuous_conversion_mode(uint32_t adc)
{
ADC_CFGR1(adc) |= ADC_CFGR1_CONT;
}
/**
* Enable Single Conversion Mode
* In this mode the ADC performs a conversion of one channel or a channel group
* and stops.
*
* @param[in] adc ADC block register address base @ref adc_reg_base
*/
void adc_set_single_conversion_mode(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_CONT;
}
/** @brief ADC Set Resolution
*
* ADC Resolution can be reduced from 12 bits to 10, 8 or 6 bits for a
* corresponding reduction in conversion time.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] resolution Unsigned int16. Resolution value (@ref adc_api_res)
*/
void adc_set_resolution(uint32_t adc, uint16_t resolution)
{
ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_RES_MASK) | resolution;
}
/** @brief ADC Set the Data as Left Aligned
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_set_left_aligned(uint32_t adc)
{
ADC_CFGR1(adc) |= ADC_CFGR1_ALIGN;
}
/** @brief ADC Set the Data as Right Aligned
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_set_right_aligned(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_ALIGN;
}
/** @brief ADC Enable DMA Transfers
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_enable_dma(uint32_t adc)
{
ADC_CFGR1(adc) |= ADC_CFGR1_DMAEN;
}
/** @brief ADC Disable DMA Transfers
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_dma(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_DMAEN;
}
/** @brief ADC Enable the Overrun Interrupt
*
* The overrun interrupt is generated when data is not read from a result
* register before the next conversion is written. If DMA is enabled, all
* transfers are terminated and any conversion sequence is aborted.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_enable_overrun_interrupt(uint32_t adc)
{
ADC_IER(adc) |= ADC_IER_OVRIE;
}
/** @brief ADC Disable the Overrun Interrupt
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_overrun_interrupt(uint32_t adc)
{
ADC_IER(adc) &= ~ADC_IER_OVRIE;
}
/** @brief ADC Read the Overrun Flag
*
* The overrun flag is set when data is not read from a result register before
* the next conversion is written. If DMA is enabled, all transfers are
* terminated and any conversion sequence is aborted.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
bool adc_get_overrun_flag(uint32_t adc)
{
return ADC_ISR(adc) & ADC_ISR_OVR;
}
/** @brief ADC Clear Overrun Flags
*
* The overrun flag is cleared. Note that if an overrun occurs, DMA is
* terminated.
* The flag must be cleared and the DMA stream and ADC reinitialised to resume
* conversions (see the reference manual).
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_clear_overrun_flag(uint32_t adc)
{
ADC_ISR(adc) = ADC_ISR_OVR;
}
/** @brief ADC Enable Regular End-Of-Conversion Interrupt
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_enable_eoc_interrupt(uint32_t adc)
{
ADC_IER(adc) |= ADC_IER_EOCIE;
}
/** @brief ADC Disable Regular End-Of-Conversion Interrupt
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_eoc_interrupt(uint32_t adc)
{
ADC_IER(adc) &= ~ADC_IER_EOCIE;
}
/** @brief ADC Read from the Regular Conversion Result Register
*
* The result read back is 12 bits, right or left aligned within the first
* 16 bits.
*
* @param[in] adc Unsigned int32. ADC block register address base
* @ref adc_reg_base
* @returns Unsigned int32 conversion result.
*/
uint32_t adc_read_regular(uint32_t adc)
{
return ADC_DR(adc);
}
/**
* Enable the temperature sensor (only)
* The channel this is available on is unfortunately not
* consistent, even though the bit used to enable it is.
* @sa adc_disable_temperature_sensor
*/
void adc_enable_temperature_sensor(void)
{
ADC_CCR(ADC1) |= ADC_CCR_TSEN;
}
/**
* Disable the temperature sensor (only)
* @sa adc_enable_temperature_sensor
*/
void adc_disable_temperature_sensor(void)
{
ADC_CCR(ADC1) &= ~ADC_CCR_TSEN;
}
/**
* Enable the internal voltage reference (only)
* The channel this is available on is unfortunately not
* consistent, even though the bit used to enable it is.
* FIXME - on f3, you can actually have it on ADC34 as well!
* @sa adc_disable_vrefint
*/
void adc_enable_vrefint(void)
{
ADC_CCR(ADC1) |= ADC_CCR_VREFEN;
}
/**
* Disable the internal voltage reference (only)
* @sa adc_enable_vrefint
*/
void adc_disable_vrefint(void)
{
ADC_CCR(ADC1) &= ~ADC_CCR_VREFEN;
}
/** @brief ADC Software Triggered Conversion on Regular Channels
*
* This starts conversion on a set of defined regular channels.
* Depending on the configuration bits EXTEN, a conversion will start
* immediately (software trigger configuration) or once a regular hardware
* trigger event occurs (hardware trigger configuration)
*
* @param[in] adc ADC block register address base @ref adc_reg_base
*/
void adc_start_conversion_regular(uint32_t adc)
{
/* Start conversion on regular channels. */
ADC_CR(adc) |= ADC_CR_ADSTART;
}
/** @brief Enable circular mode for DMA transfers
*
* For this to work it needs to be ebabled on the DMA side as well.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_enable_dma_circular_mode(uint32_t adc)
{
ADC_CFGR1(adc) |= ADC_CFGR1_DMACFG;
}
/** @brief Disable circular mode for DMA transfers
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_dma_circular_mode(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_DMACFG;
}
/** Enable Delayed Conversion Mode.
*
* @param[in] adc ADC block register address base @ref adc_reg_base
*/
void adc_enable_delayed_conversion_mode(uint32_t adc)
{
ADC_CFGR1(adc) |= ADC_CFGR1_AUTDLY;
}
/** Enable Delayed Conversion Mode.
*
* @param[in] adc ADC block register address base @ref adc_reg_base
*/
void adc_disable_delayed_conversion_mode(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_AUTDLY;
}
/**@}*/

View File

@@ -0,0 +1,133 @@
/** @addtogroup adc_file ADC peripheral API
@ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly
2016 Karl Palsson <karlp@tweak.net.au>
This provides the "multi" extensions to the "v2" ADC peripheral. This is those
devices that support injected channels and per channel sampling times.
At the time of writing, this is the STM32F30x and the STM32L4x
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2016 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/adc.h>
/** @brief ADC Set the Sample Time for a Single Channel
*
* The sampling time can be selected in ADC clock cycles, exact values
* depend on the device.
*
* @param[in] adc ADC block register address base @ref adc_reg_base
* @param[in] channel ADC Channel integer @ref adc_channel
* @param[in] time Sampling time selection from @ref adc_sample
*/
void adc_set_sample_time(uint32_t adc, uint8_t channel, uint8_t time)
{
uint32_t reg32;
if (channel < 10) {
reg32 = ADC_SMPR1(adc);
reg32 &= ~(0x7 << (channel * 3));
reg32 |= (time << (channel * 3));
ADC_SMPR1(adc) = reg32;
} else {
reg32 = ADC_SMPR2(adc);
reg32 &= ~(0x7 << ((channel - 10) * 3));
reg32 |= (time << ((channel - 10) * 3));
ADC_SMPR2(adc) = reg32;
}
}
/** @brief ADC Set the Sample Time for All Channels
*
* The sampling time can be selected in ADC clock cycles, exact values
* depend on the device.
*
* @param[in] adc ADC block register address base @ref adc_reg_base
* @param[in] time Sampling time selection from @ref adc_sample
*/
void adc_set_sample_time_on_all_channels(uint32_t adc, uint8_t time)
{
uint8_t i;
uint32_t reg32 = 0;
for (i = 0; i <= 9; i++) {
reg32 |= (time << (i * 3));
}
ADC_SMPR1(adc) = reg32;
for (i = 10; i <= 17; i++) {
reg32 |= (time << ((i - 10) * 3));
}
ADC_SMPR2(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 ADC block register address base @ref adc_reg_base
* @param[in] length Number of channels in the group, range 0..16
* @param[in] channel Set of channels in sequence, range @ref adc_channel
*/
void adc_set_regular_sequence(uint32_t adc, uint8_t length, uint8_t channel[])
{
uint32_t reg32_1 = 0, reg32_2 = 0, reg32_3 = 0, reg32_4 = 0;
uint8_t i = 0;
/* Maximum sequence length is 16 channels. */
if (length > 16) {
return;
}
for (i = 1; i <= length; i++) {
if (i <= 4) {
reg32_1 |= (channel[i - 1] << (i * 6));
}
if ((i > 4) && (i <= 9)) {
reg32_2 |= (channel[i - 1] << ((i - 4 - 1) * 6));
}
if ((i > 9) && (i <= 14)) {
reg32_3 |= (channel[i - 1] << ((i - 9 - 1) * 6));
}
if ((i > 14) && (i <= 16)) {
reg32_4 |= (channel[i - 1] << ((i - 14 - 1) * 6));
}
}
reg32_1 |= ((length - 1) << ADC_SQR1_L_SHIFT);
ADC_SQR1(adc) = reg32_1;
ADC_SQR2(adc) = reg32_2;
ADC_SQR3(adc) = reg32_3;
ADC_SQR4(adc) = reg32_4;
}
/**@}*/

View File

@@ -0,0 +1,487 @@
/** @addtogroup cordic_file CORDIC peripheral API
@ingroup peripheral_apis
@brief HW accelerated maths trig/hyperbolic operations.
@author @htmlonly &copy; @endhtmlonly
2022 Oskar H. Maier <ohma@posteo.de>
This library supports the CORDIC co-processor in the STM32 series of
ARM Cortex Microcontrollers by ST Microelectronics. This peripheral
computes trigonometric and hyperbolic functions and converts between
cartesian and polar coordinates.
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2022 Oskar H. Maier <ohma@posteo.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/cordic.h>
/** @brief Read CORDIC result ready flag
*
* This flag is set by hardware when a CORDIC operation completes.
* It is automatically cleared when all results have been read.
*
* @returns Result ready flag.
*/
bool cordic_is_result_ready(void) {
return CORDIC_CSR & CORDIC_CSR_RRDY;
}
/** @brief Set CORDIC to 32 bit argument data width.
*
* When configured this way, argument(s) are expected with 32 bit width.
* Two write operations are required for operations with two arguments.
*
*/
void cordic_set_argument_width_32bit(void) {
CORDIC_CSR &= ~CORDIC_CSR_ARGSIZE;
}
/** @brief Set CORDIC to 16 bit argument data width.
*
* When configured this way, argument(s) are expected with 16 bit width.
* Only one 32 bit write operation is required even for operations with two arguments
* (in this case lower 16 bits contain argument 1, higher 16 bits contain argument 2).
*
*/
void cordic_set_argument_width_16bit(void) {
CORDIC_CSR |= CORDIC_CSR_ARGSIZE;
}
/** @brief Set CORDIC to 32 bit result data width.
*
* When configured this way, results(s) are written with 32 bit width.
* Two read operations are required for operations with two results.
*
*/
void cordic_set_result_width_32bit(void) {
CORDIC_CSR &= ~CORDIC_CSR_RESSIZE;
}
/** @brief Set CORDIC to 16 bit result data width.
*
* When configured this way, results are written with 16 bit width.
* Only one 32 bit read operation is required even for operations with two results
* (in this case lower 16 bits contain result 1, higher 16 bits contain result 2).
*
*/
void cordic_set_result_width_16bit(void) {
CORDIC_CSR |= CORDIC_CSR_RESSIZE;
}
/** @brief Set number of CORDIC arguments to one 32 bit argument or two 16 bit arguments.
*
* Use this option for CORDIC operations with only one argument and CORDIC operations
* with two 16 bit arguments. In this case the operation is triggered
* as soon as one 32bit write to the CORDIC_WDATA register occurred.
*
*/
void cordic_set_number_of_arguments_1(void) {
CORDIC_CSR &= ~CORDIC_CSR_NARGS;
}
/** @brief Set number of CORDIC arguments to two 32 bit arguments.
*
* Use this option for CORDIC operations with two 32 bit arguments.
* In this case the operation is triggered as soon as two 32bit
* writes to the CORDIC_WDATA register occurred.
*
*/
void cordic_set_number_of_arguments_2(void) {
CORDIC_CSR |= CORDIC_CSR_NARGS;
}
/** @brief Set number of CORDIC results to one 32 bit result or two 16 bit results.
*
* Use this option for CORDIC operations with only one result and CORDIC operations
* with two 16 bit results. In this case the result ready flag is cleared and a new operation
* can be started as soon as one 32bit read from the CORDIC_RDATA register occurred.
*
*/
void cordic_set_number_of_results_1(void) {
CORDIC_CSR &= ~CORDIC_CSR_NRES;
}
/** @brief Set number of CORDIC results to two 32 bit results.
*
* Use this option for CORDIC operations with two 32 bit results.
* In this case the result ready flag is cleared and a new operation can be started
* as soon as two 32 bit reads from the CORDIC_RDATA register occurred.
*
*/
void cordic_set_number_of_results_2(void) {
CORDIC_CSR |= CORDIC_CSR_NRES;
}
/** @brief Enable DMA for writes to CORDIC_WDATA
*
* When enabled, the peripheral will continue to generate DMA requests
* when new arguments can be loaded into the CORDIC_WDATA register.
*
*/
void cordic_enable_dma_write(void) {
CORDIC_CSR |= CORDIC_CSR_DMAWEN;
}
/** @brief Disable DMA for writes to CORDIC_WDATA
*
* When disabled, the peripheral will not generate DMA requests
* when new arguments can be loaded into the CORDIC_WDATA register.
*
*/
void cordic_disable_dma_write(void) {
CORDIC_CSR &= ~CORDIC_CSR_DMAWEN;
}
/** @brief Enable DMA for read from CORDIC_RDATA
*
* When enabled, the peripheral will continue to generate DMA requests
* when new results can be read from the CORDIC_RDATA register.
*
*/
void cordic_enable_dma_read(void) {
CORDIC_CSR |= CORDIC_CSR_DMAREN;
}
/** @brief Disable DMA for read from CORDIC_RDATA
*
* When disabled, the peripheral will not generate DMA requests
* when new results can be read from the CORDIC_RDATA register.
*
*/
void cordic_disable_dma_read(void) {
CORDIC_CSR &= ~CORDIC_CSR_DMAREN;
}
/** @brief Enable interrupt when result is ready
*
* When enabled, the peripheral will generate an interrupt
* when the CORDIC_CSR_RRDY flag is set.
*
*/
void cordic_enable_interrupt(void) {
CORDIC_CSR |= CORDIC_CSR_IEN;
}
/** @brief Set scaling factor for CORDIC operations
*
* For some operations, the arguments can be multiplied by a factor of 2^-n
* to fit in the argument range. The result must then be multiplied by 2^n.
* @param[in] n scaling factor of type @ref cordic_csr_scale
*
*/
void cordic_set_scaling_factor(uint8_t n) {
CORDIC_CSR = (CORDIC_CSR & ~CORDIC_CSR_SCALE_MASK) | (n << CORDIC_CSR_SCALE_SHIFT);
}
/** @brief Set precision for CORDIC operations
*
* The speed of CORDIC operations can be increased by lowering the
* number of iterations. This will decrease precision.
* @param[in] precision precision of type @ref cordic_csr_precision
*
*/
void cordic_set_precision(uint8_t precision) {
CORDIC_CSR = (CORDIC_CSR & ~CORDIC_CSR_PRECISION_MASK) | (precision << CORDIC_CSR_PRECISION_SHIFT);
}
/** @brief Set CORDIC operation type
*
* Select what operation the CORDIC peripheral performs.
* @param[in] function function of type @ref cordic_csr_function
*
*/
void cordic_set_function(uint8_t function) {
CORDIC_CSR = (CORDIC_CSR & ~CORDIC_CSR_FUNC_MASK) | (function << CORDIC_CSR_FUNC_SHIFT);
}
/** @brief Write single 16 bit argument
*
* Use this function to set one single 16 bit argument.
* The upper 16 bit of the 32 bit result register
* (that is the second argument) will be set to zero.
* @param[in] argument argument
*
*/
void cordic_write_16bit_argument(uint16_t argument) {
CORDIC_WDATA = argument;
}
/** @brief Write two 16 bit arguments
*
* Use this function to set write 16 bit arguments to the 32 bit CORDIC_WDATA register.
* @param[in] argument1 argument1
* @param[in] argument2 argument2
*
*/
void cordic_write_16bit_arguments(uint16_t argument1, uint16_t argument2) {
CORDIC_WDATA = argument2 << 16 | argument1;
}
/** @brief Write single 32 bit argument
*
* Use this function to write a 32 bit argument to the CORDIC_WDATA register.
* If the operation needs two arguments call cordic_set_number_of_arguments_2()
* before and then use this function twice to write both arguments.
* @param[in] argument argument
*
*/
void cordic_write_32bit_argument(uint32_t argument) {
CORDIC_WDATA = argument;
}
/** @brief Read single 16 bit result
*
* Use this function to read one single 16 bit result contained
* in the lower 16 bit of the CORDIC_RDATA register.
* @returns result
*
*/
uint16_t cordic_read_16bit_result(void) {
return CORDIC_RDATA;
}
/** @brief Read two 16 bit results
*
* Use this function to read both 16 bit results contained
* in the 32 bit CORDIC_RDATA register.
* @param[out] result1 First result is written to this address
* @param[out] result2 Second result is written to this address
*
*/
void cordic_read_16bit_results(uint16_t *result1, uint16_t *result2) {
uint32_t temp = CORDIC_RDATA;
*result1 = temp;
*result2 = temp >> 16;
}
/** @brief Read 32 bit result
*
* Use this function to read the 32 bit CORDIC_RDATA register.
* @returns result
*
*/
uint32_t cordic_read_32bit_result(void) {
return CORDIC_RDATA;
}
/** @brief Configure cordic for 16 bit cosine
*
* Configures cordic peripheral to perform 16 bit cosine operation without triggering it
*
*/
void cordic_configure_for_cos_16bit(void) {
cordic_set_function(CORDIC_CSR_FUNC_COS);
cordic_set_precision(CORDIC_CSR_PRECISION_ITER_20);
cordic_set_argument_width_16bit();
cordic_set_result_width_16bit();
cordic_set_number_of_arguments_1();
cordic_set_number_of_results_1();
/* scale is not applicable for cos */
}
/** @brief Configure cordic for 32 bit cosine
*
* Configures cordic peripheral to perform 32 bit cosine operation without triggering it
*
*/
void cordic_configure_for_cos_32bit(void) {
cordic_set_function(CORDIC_CSR_FUNC_COS);
cordic_set_precision(CORDIC_CSR_PRECISION_ITER_28);
cordic_set_argument_width_32bit();
cordic_set_result_width_32bit();
cordic_set_number_of_arguments_1();
cordic_set_number_of_results_1();
/* scale is not applicable for cos */
}
/** @brief Configure cordic for 16 bit sine
*
* Configures cordic peripheral to perform 16 bit sine operation without triggering it
*
*/
void cordic_configure_for_sin_16bit(void) {
cordic_set_function(CORDIC_CSR_FUNC_SIN);
cordic_set_precision(CORDIC_CSR_PRECISION_ITER_20);
cordic_set_argument_width_16bit();
cordic_set_result_width_16bit();
cordic_set_number_of_arguments_1();
cordic_set_number_of_results_1();
/* scale is not applicable for sin */
}
/** @brief Configure cordic for 32 bit sine
*
* Configures cordic peripheral to perform 32 bit sine operation without triggering it
*
*/
void cordic_configure_for_sin_32bit(void) {
cordic_set_function(CORDIC_CSR_FUNC_SIN);
cordic_set_precision(CORDIC_CSR_PRECISION_ITER_28);
cordic_set_argument_width_32bit();
cordic_set_result_width_32bit();
cordic_set_number_of_arguments_1();
cordic_set_number_of_results_1();
/* scale is not applicable for sin */
}
/** @brief Compute 16 bit cosine using CORDIC (blocking)
*
* Convenience function to calculate 32767*cos(x/32767*pi).
* This implementation can be sped up in most applications by configuring the peripheral only once
* and then trigger subsequent operations by writing new arguments to the CORDIC_WDATA register.
* Additionally, sine and cosine are always computed in a single operation.
* Read the second result to obtain the other value.
* @param[in] x argument
* @returns result
*
*/
int16_t cordic_cos_16bit(int16_t x) {
cordic_configure_for_cos_16bit();
cordic_write_16bit_arguments((uint16_t) x, 0x7FFF);
/* this while loop can be omitted but that will stall the
processor while it waits for the CORDIC_RDATA register */
while(!cordic_is_result_ready());
return cordic_read_16bit_result();
}
/** @brief Compute 16 bit cosine using CORDIC (non blocking)
*
* Convenience function to calculate 32767*cos(x/32767*pi).
* Result can be obtained from result register using cordic_read_16bit_result().
*
* @param[in] x argument
*
*/
void cordic_cos_16bit_async(int16_t x) {
cordic_configure_for_cos_16bit();
cordic_write_16bit_arguments((uint16_t) x, 0x7FFF);
}
/** @brief Compute 32 bit cosine using CORDIC (blocking)
*
* Convenience function to calculate 2147483647*cos(x/2147483647*pi).
* This implementation can be sped up in most applications by configuring the peripheral only once
* and then trigger subsequent operations by writing new arguments to the CORDIC_WDATA register.
* Additionally, sine and cosine are always computed in a single operation.
* Read the second result to obtain the other value.
* @param[in] x argument
* @returns result
*
*/
int32_t cordic_cos_32bit(int32_t x) {
cordic_configure_for_cos_32bit();
cordic_write_32bit_argument((uint32_t) x);
while(!cordic_is_result_ready());
return cordic_read_32bit_result();
}
/** @brief Compute 32 bit cosine using CORDIC (non blocking)
*
* Convenience function to calculate 2147483647*cos(x/2147483647*pi).
* Result can be obtained from result register using cordic_read_32bit_result().
*
* @param[in] x argument
*
*/
void cordic_cos_32bit_async(int32_t x) {
cordic_configure_for_cos_32bit();
cordic_write_32bit_argument((uint32_t) x);
}
/** @brief Compute 16 bit sine using CORDIC (blocking)
*
* Convenience function to calculate 32767*sin(x/32767*pi).
* This implementation can be sped up in most applications by configuring the peripheral only once
* and then trigger subsequent operations by writing new arguments to the CORDIC_WDATA register.
* Additionally, sine and cosine are always computed in a single operation.
* Read the second result to obtain the other value.
* @param[in] x argument
* @returns result
*
*/
int16_t cordic_sin_16bit(int16_t x) {
cordic_configure_for_sin_16bit();
cordic_write_16bit_arguments((uint16_t) x, 0x7FFF);
/* this while loop can be omitted but that will stall the
processor while it waits for the CORDIC_RDATA register */
while(!cordic_is_result_ready());
return cordic_read_16bit_result();
}
/** @brief Compute 16 bit sine using CORDIC (non blocking)
*
* Convenience function to calculate 32767*sin(x/32767*pi).
* Result can be obtained from result register using cordic_read_16bit_result().
*
* @param[in] x argument
*
*/
void cordic_sin_16bit_async(int16_t x) {
cordic_configure_for_sin_16bit();
cordic_write_16bit_arguments((uint16_t) x, 0x7FFF);
}
/** @brief Compute 32 bit sine using CORDIC (blocking)
*
* Convenience function to calculate 2147483647*sin(x/2147483647*pi).
* This implementation can be sped up in most applications by configuring the peripheral only once
* and then trigger subsequent operations by writing new arguments to the CORDIC_WDATA register.
* Additionally, sine and cosine are always computed in a single operation.
* Read the second result to obtain the other value.
* @param[in] x argument
* @returns result
*
*/
int32_t cordic_sin_32bit(int32_t x) {
cordic_configure_for_sin_32bit();
cordic_write_32bit_argument((uint32_t) x);
/* this while loop can be omitted but that will stall the
processor while it waits for the CORDIC_RDATA register */
while(!cordic_is_result_ready());
return cordic_read_32bit_result();
}
/** @brief Compute 32 bit sine using CORDIC (non blocking)
*
* Convenience function to calculate 2147483647*sin(x/2147483647*pi).
* Result can be obtained from result register using cordic_read_32bit_result().
*
* @param[in] x argument
*
*/
void cordic_sin_32bit_async(int32_t x) {
cordic_configure_for_sin_32bit();
cordic_write_32bit_argument((uint32_t) x);
}

View File

@@ -0,0 +1,54 @@
/** @addtogroup crc_file CRC peripheral API
@ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2012 Karl Palsson <karlp@remake.is>
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@remake.is>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/crc.h>
/**@{*/
void crc_reset(void)
{
CRC_CR |= CRC_CR_RESET;
}
uint32_t crc_calculate(uint32_t data)
{
CRC_DR = data;
/* Data sheet says this blocks until it's ready.... */
return CRC_DR;
}
uint32_t crc_calculate_block(uint32_t *datap, int size)
{
int i;
for (i = 0; i < size; i++) {
CRC_DR = datap[i];
}
return CRC_DR;
}
/**@}*/

View File

@@ -0,0 +1,116 @@
/** @addtogroup crc_file CRC peripheral API
@ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2016 Cem Basoglu <cem.basoglu@web.de>
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2016 Cem Basoglu <cem.basoglu@web.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/crc.h>
/*---------------------------------------------------------------------------*/
/** @brief Enable reverse output data.
Enables the reversal of the bit order of the output data.
*/
void crc_reverse_output_enable()
{
CRC_CR |= CRC_CR_REV_OUT;
}
/*---------------------------------------------------------------------------*/
/** @brief Disable reverse output data.
Disables the reversal of the bit order of the output data.
*/
void crc_reverse_output_disable()
{
CRC_CR &= ~CRC_CR_REV_OUT;
}
/*---------------------------------------------------------------------------*/
/** @brief Reverse input data.
Controls the reversal of the bit order of the input data
@param[in] reverse_in Unsigned int32. Reversal bit order @ref crc_rev_in.
*/
void crc_set_reverse_input(uint32_t reverse_in)
{
uint32_t reg32 = CRC_CR;
reg32 = (reg32 & ~CRC_CR_REV_IN) | reverse_in;
CRC_CR = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief Polynomial size
Set the size of the polynomial.
@param[in] polysize Unsigned int32. Size of polynomial @ref crc_polysize.
*/
void crc_set_polysize(uint32_t polysize)
{
uint32_t reg32 = CRC_CR;
reg32 = (reg32 & ~CRC_CR_POLYSIZE) | polysize;
CRC_CR = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief Polynomial coefficient
Set the coefficients of the polynomial to be used for CRC calculation.
If the polynomial size is less than 32-bits, the least significant bits
have to be used to program the correct value.
@note To obtain a reliable CRC calculation, any changes to the polynomial
value or size can not be performed during a CRC calculation.
As a result, if a CRC calculation is ongoing, the application must either
reset the crc unit it or perform a CRC_DR read before changing the polynomial.
@note The default polynomial value is the CRC-32 (Ethernet) polynomial: 0x4C11DB7.
@param[in] polynomial Unsigned int32. Polynomial coefficient.
*/
void crc_set_polynomial(uint32_t polynomial)
{
CRC_POL = polynomial;
}
/*---------------------------------------------------------------------------*/
/** @brief CRC Initial value.
Sets the crc initial value.
@param[in] initial Unsigned int32. CRC initial value.
*/
void crc_set_initial(uint32_t initial)
{
CRC_INIT = initial;
}
/**@}*/

View File

@@ -0,0 +1,50 @@
/** @addtogroup crs_file CRS peripheral API
* @ingroup peripheral_apis
*
* @brief <b>(USB) STM32 Clock Recovery Subsystem</b>
*
* @version 1.0.0
*
* @date 5 Feb 2014
*
* 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/crs.h>
#include <libopencm3/stm32/rcc.h>
/**
* This function enables automatic trimming of internal RC oscillator by USB SOF
* frames
*/
void crs_autotrim_usb_enable(void)
{
rcc_periph_clock_enable(RCC_CRS);
CRS_CFGR &= ~CRS_CFGR_SYNCSRC;
CRS_CFGR |= CRS_CFGR_SYNCSRC_USB_SOF;
CRS_CR |= CRS_CR_AUTOTRIMEN;
CRS_CR |= CRS_CR_CEN;
}
/**@}*/

View File

@@ -0,0 +1,175 @@
/** @addtogroup crypto_file
*
* @brief <b>libopencm3 STM32 Cryptographic controller</b>
*
* @version 1.0.0
*
* @date 17 Jun 2013
*
* This library supports the cryptographic coprocessor system for the
* STM32 series of ARM Cortex Microcontrollers
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/crypto.h>
#define CRYP_CR_ALGOMODE_MASK ((1 << 19) | CRYP_CR_ALGOMODE)
/**
* @brief Wait, if the Controller is busy
*/
void crypto_wait_busy(void)
{
while (CRYP_SR & CRYP_SR_BUSY);
}
/**
* @brief Set key value to the controller
* @param[in] keysize enum crypto_keysize Specified size of the key.
* @param[in] key uint64_t[] Key value (array of 4 items)
*/
void crypto_set_key(enum crypto_keysize keysize, uint64_t key[])
{
int i;
crypto_wait_busy();
CRYP_CR = (CRYP_CR & ~CRYP_CR_KEYSIZE) |
(keysize << CRYP_CR_KEYSIZE_SHIFT);
for (i = 0; i < 4; i++) {
CRYP_KR(i) = key[i];
}
}
/**
* @brief Set Initialization Vector
*
* @param[in] iv uint64_t[] Initialization vector (array of 4 items)
* @note Cryptographic controller must be in disabled state
*/
void crypto_set_iv(uint64_t iv[])
{
int i;
crypto_wait_busy();
for (i = 0; i < 4; i++) {
CRYP_IVR(i) = iv[i];
}
}
/**
* @brief Set the order of the data to be crypted
*
* @param[in] datatype enum crypto_datatype Specified datatype of the key.
*/
void crypto_set_datatype(enum crypto_datatype datatype)
{
CRYP_CR = (CRYP_CR & ~CRYP_CR_DATATYPE) |
(datatype << CRYP_CR_DATATYPE_SHIFT);
}
/**
* @brief Set the algorithm for Encryption/decryption
*
*@param[in] mode enum crypto_mode Mode of execution
*/
void crypto_set_algorithm(enum crypto_mode mode)
{
mode &= ~CRYP_CR_ALGOMODE_MASK;
if ((mode == DECRYPT_AES_ECB) || (mode == DECRYPT_AES_CBC)) {
/* Unroll keys for the AES encoder for the user automatically */
CRYP_CR = (CRYP_CR & ~CRYP_CR_ALGOMODE_MASK) |
CRYP_CR_ALGOMODE_AES_PREP;
crypto_start();
crypto_wait_busy();
/* module switches to DISABLE automatically */
}
/* set algo mode */
CRYP_CR = (CRYP_CR & ~CRYP_CR_ALGOMODE_MASK) | mode;
/* flush buffers */
CRYP_CR |= CRYP_CR_FFLUSH;
}
/**
* @brief Enable the cryptographic controller and start processing
*/
void crypto_start(void)
{
CRYP_CR |= CRYP_CR_CRYPEN;
}
/**
* @brief Disable the cryptographic controller and stop processing
*/
void crypto_stop(void)
{
CRYP_CR &= ~CRYP_CR_CRYPEN;
}
/**
* @brief Start of encryption or decryption on data buffers
*
* This blocking method transfers input buffer of specified length to the
* cryptographic coprocessor, and instructs him to begin of ciphering or
* deciphering. It waits for data to be ready, and then fills the processed
* data to output buffer.
*
* @param[in] inp uint32_t* Input array to crypt/decrypt.
* @param[in] outp uint32_t* Output array with crypted/encrypted data.
* @param[in] length uint32_t Length of the arrays
*
* @returns uint32_t Number of written words
*/
uint32_t crypto_process_block(uint32_t *inp, uint32_t *outp, uint32_t length)
{
uint32_t rd = 0, wr = 0;
/* Transfer the data */
while (rd != length) {
if ((wr < length) && (CRYP_SR & CRYP_SR_IFNF)) {
CRYP_DIN = *inp++;
wr++;
}
if (CRYP_SR & CRYP_SR_OFNE) {
*outp++ = CRYP_DOUT;
rd++;
}
}
/* Wait to finish - Not needed ? */
crypto_wait_busy();
return wr;
}
/**@}*/

View File

@@ -0,0 +1,487 @@
/** @addtogroup dac_file DAC peripheral API
* @ingroup peripheral_apis
* @brief Digital to Analog Converter
@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies <ksarkies@internode.on.net>
@author @htmlonly &copy; @endhtmlonly 2020 Ben Brewer <ben.brewer@codethink.co.uk>
This library supports the Digital to Analog Conversion System in the
STM32 series of ARM Cortex Microcontrollers by ST Microelectronics.
The DAC peripheral found on many of the devices in the STM32 lineup,
sometimes with only one channel, but normally with two channels.
Two DAC channels are available, however unlike the ADC channels these
are separate DAC devices controlled by the same register block.
The DAC is on APB1. Its clock must be enabled in RCC and depending on
specific family, the GPIO
ports set to alternate function output before it can be used.
On most families, the GPIO pins should be configured to Analog IN to
avoid parasitic consumption.
The digital output driver is disabled so the output driver mode
(push-pull/open drain) is arbitrary.
The DAC has a holding (buffer) register and an output register from
which the analog output is derived. The holding register must be
loaded first. If triggering is enabled the output register is loaded
from the holding register after a trigger occurs. If triggering is
not enabled the holding register contents are transferred directly
to the output register.
@note To avoid nonlinearities, do not allow outputs to range close
to zero or V_analog.
@section dac_api_dual Dual Channel Conversion
There are dual modes in which both DACs are used to output data
simultaneously or independently on both channels. The data must be
presented according to the formats described in the datasheets. A
convenience function @ref dac_load_data_buffer_dual is provided
for software controlled use.
A variety of modes are available depending on whether independent
or simultaneous output is desired, and whether waveforms are to be
superimposed. Refer to the datasheets.
If DMA is used, only enable it for one of the channels. The DMA
requests will then serve data in dual format to the data register
dedicated to dual mode. The data will then be split and loaded to the
appropriate DAC following the next trigger. There are three registers
available, one for each of the formats: 12 bit right-aligned, 12 bit
left-aligned and 8 bit right-aligned. The desired format is determined
by specifying the appropriate register to the DMA controller.
@section dac_api_basic_ex Basic DAC handling API.
Set the DAC's GPIO port to Analog IN. Enable the
DAC clock. Enable the DAC, set a trigger source and load the buffer
with the first value. After the DAC is triggered, load the buffer with
the next value. This example uses software triggering and added noise.
The trigger and further buffer load calls are made when data is to be
sent out.
@code
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO4);
rcc_periph_clock_enable(RCC_DAC);
dac_disable(DAC1, DAC_CHANNEL1);
dac_set_waveform_characteristics(DAC1, DAC_CHANNEL1, DAC_CR_MAMP1_8);
dac_set_waveform_generation(DAC1, DAC_CHANNEL1, DAC_CR_WAVE1_NOISE);
dac_enable(DAC1, DAC_CHANNEL1);
dac_set_trigger_source(DAC1, DAC_CR_TSEL1_SW);
dac_load_data_buffer_single(DAC1, 0, DAC_ALIGN_RIGHT12, DAC_CHANNEL1);
....
dac_software_trigger(DAC1, DAC_CHANNEL1);
dac_load_data_buffer_single(DAC1, value,
DAC_ALIGN_RIGHT12, DAC_CHANNEL1);
@endcode
@section dac_api_dma_ex Simultaneous Dual DAC with DMA.
This example in part sets up the DAC channel 1 DMA (DMA2 channel 3) to read
16 bit data from memory into the right-aligned 8 bit dual register DAC_DHR8RD.
Both DAC channels are enabled, and both triggers are set to the same timer
2 input as required for simultaneous operation. DMA is enabled for DAC channel
1 only to ensure that only one DMA request is generated.
@code
dma_set_memory_size(DMA2, DMA_CHANNEL3, DMA_CCR_MSIZE_16BIT);
dma_set_peripheral_size(DMA2, DMA_CHANNEL3, DMA_CCR_PSIZE_16BIT);
dma_set_read_from_memory(DMA2, DMA_CHANNEL3);
dma_set_peripheral_address(DMA2, DMA_CHANNEL3,(uint32_t) &DAC_DHR8RD);
dma_enable_channel(DMA2, DMA_CHANNEL3);
...
dac_trigger_enable(DAC1, DAC_CHANNEL_BOTH);
dac_set_trigger_source(DAC1, DAC_CR_TSEL1_T2 | DAC_CR_TSEL2_T2);
dac_dma_enable(DAC1, DAC_CHANNEL1);
dac_enable(DAC1, DAC_CHANNEL_BOTH);
@endcode
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Ken Sarkies
* Copyright (C) 2020 Ben Brewer
*
* 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>
/** @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 the base address of the DAC @ref dac_reg_base
@param[in] channel with DAC mask. @ref dac_channel_id
*/
void dac_enable(uint32_t dac, int channel)
{
switch (channel) {
case DAC_CHANNEL1:
DAC_CR(dac) |= DAC_CR_EN1;
break;
case DAC_CHANNEL2:
DAC_CR(dac) |= DAC_CR_EN2;
break;
case DAC_CHANNEL_BOTH:
DAC_CR(dac) |= (DAC_CR_EN1 | DAC_CR_EN2);
break;
}
}
/** @brief DAC Channel Disable.
Disable a digital to analog converter channel.
@param[in] dac the base address of the DAC @ref dac_reg_base
@param[in] channel with DAC mask @ref dac_channel_id
*/
void dac_disable(uint32_t dac, int channel)
{
switch (channel) {
case DAC_CHANNEL1:
DAC_CR(dac) &= ~DAC_CR_EN1;
break;
case DAC_CHANNEL2:
DAC_CR(dac) &= ~DAC_CR_EN2;
break;
case DAC_CHANNEL_BOTH:
DAC_CR(dac) &= ~(DAC_CR_EN1 | DAC_CR_EN2);
break;
default:
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 the base address of the DAC. @ref dac_reg_base
@param[in] channel with DAC mask. @ref dac_channel_id
*/
void dac_dma_enable(uint32_t dac, int channel)
{
switch (channel) {
case DAC_CHANNEL1:
DAC_CR(dac) |= DAC_CR_DMAEN1;
break;
case DAC_CHANNEL2:
DAC_CR(dac) |= DAC_CR_DMAEN2;
break;
case DAC_CHANNEL_BOTH:
DAC_CR(dac) |= (DAC_CR_DMAEN1 | DAC_CR_DMAEN2);
break;
default:
break;
}
}
/** @brief DAC Channel DMA Disable.
Disable a digital to analog converter channel DMA mode.
@param[in] dac the base address of the DAC. @ref dac_reg_base
@param[in] channel with DAC mask. @ref dac_channel_id
*/
void dac_dma_disable(uint32_t dac, int channel)
{
switch (channel) {
case DAC_CHANNEL1:
DAC_CR(dac) &= ~DAC_CR_DMAEN1;
break;
case DAC_CHANNEL2:
DAC_CR(dac) &= ~DAC_CR_DMAEN2;
break;
case DAC_CHANNEL_BOTH:
DAC_CR(dac) &= ~(DAC_CR_DMAEN1 | DAC_CR_DMAEN2);
break;
default:
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 the base address of the DAC. @ref dac_reg_base
@param[in] channel with DAC mask. @ref dac_channel_id
*/
void dac_trigger_enable(uint32_t dac, int channel)
{
switch (channel) {
case DAC_CHANNEL1:
DAC_CR(dac) |= DAC_CR_TEN1;
break;
case DAC_CHANNEL2:
DAC_CR(dac) |= DAC_CR_TEN2;
break;
case DAC_CHANNEL_BOTH:
DAC_CR(dac) |= (DAC_CR_TEN1 | DAC_CR_TEN2);
break;
default:
break;
}
}
/** @brief DAC Channel Trigger Disable.
Disable a digital to analog converter channel external trigger.
@param[in] dac the base address of the DAC. @ref dac_reg_base
@param[in] channel with DAC mask. @ref dac_channel_id
*/
void dac_trigger_disable(uint32_t dac, int channel)
{
switch (channel) {
case DAC_CHANNEL1:
DAC_CR(dac) &= ~DAC_CR_TEN1;
break;
case DAC_CHANNEL2:
DAC_CR(dac) &= ~DAC_CR_TEN2;
break;
case DAC_CHANNEL_BOTH:
DAC_CR(dac) &= ~(DAC_CR_TEN1 | DAC_CR_TEN2);
break;
default:
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 the base address of the DAC. @ref dac_reg_base
@param[in] source Taken from @ref dac_trig2_sel or @ref
dac_trig1_sel or a logical OR of one of each of these to set both channels
simultaneously.
*/
void dac_set_trigger_source(uint32_t dac, uint32_t source)
{
DAC_CR(dac) |= source;
}
/**
* Set DAC Channel Waveform Generation mode for one or both channels.
* These signals are superimposed on existing output values in the
* DAC output registers. Waveform can be disabled, noise, triangular,
* or sawtooth, depending on family.
* @note The DAC trigger must be enabled for this to work.
* @param[in] dac the base address of the DAC. @ref dac_reg_base
* @param[in] channel one or both, @ref dac_channel_id
* @param[in] wave enum ::dac_wave. mode for channel
*/
void dac_set_waveform_generation(uint32_t dac, int channel, enum dac_wave wave)
{
uint32_t reg = DAC_CR(dac);
switch(channel) {
case DAC_CHANNEL1:
reg &= ~(DAC_CR_WAVEx_MASK << DAC_CR_WAVE1_SHIFT);
reg |= wave << DAC_CR_WAVE1_SHIFT;
break;
case DAC_CHANNEL2:
reg &= ~(DAC_CR_WAVEx_MASK << DAC_CR_WAVE2_SHIFT);
reg |= wave << DAC_CR_WAVE2_SHIFT;
break;
case DAC_CHANNEL_BOTH:
reg &= ~(DAC_CR_WAVEx_MASK << DAC_CR_WAVE1_SHIFT)
| ~(DAC_CR_WAVEx_MASK << DAC_CR_WAVE2_SHIFT);
reg |= wave << DAC_CR_WAVE1_SHIFT;
reg |= wave << DAC_CR_WAVE2_SHIFT;
break;
default:
break;
}
DAC_CR(dac) = reg;
}
/**
* Disable DAC Channel Waveform Generation.
* @note this is equivalent to @ref dac_set_waveform_generation (dac, channel, DAC_WAVE_DISABLE)
* @param[in] dac the base address of the DAC. @ref dac_reg_base
* @param[in] channel with DAC mask. @ref dac_channel_id
*/
void dac_disable_waveform_generation(uint32_t dac, int channel)
{
dac_set_waveform_generation(dac, channel, DAC_WAVE_DISABLE);
}
/** @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 the base address of the DAC. @ref dac_reg_base
@param[in] channel one or both, select from @ref dac_channel_id
@param[in] mamp amplitude of mixed waveform, bit width @ref DAC_CR_MAMPx_MASK
*/
void dac_set_waveform_characteristics(uint32_t dac, int channel, int mamp)
{
uint32_t reg = DAC_CR(dac);
switch(channel) {
case DAC_CHANNEL1:
reg &= ~(DAC_CR_MAMPx_MASK << DAC_CR_MAMP1_SHIFT);
reg |= mamp << DAC_CR_MAMP1_SHIFT;
break;
case DAC_CHANNEL2:
reg &= ~(DAC_CR_MAMPx_MASK << DAC_CR_MAMP2_SHIFT);
reg |= mamp << DAC_CR_MAMP2_SHIFT;
break;
case DAC_CHANNEL_BOTH:
reg &= ~(DAC_CR_MAMPx_MASK << DAC_CR_MAMP1_SHIFT)
| ~(DAC_CR_MAMPx_MASK << DAC_CR_MAMP2_SHIFT);
reg |= mamp << DAC_CR_MAMP1_SHIFT;
reg |= mamp << DAC_CR_MAMP2_SHIFT;
break;
default:
break;
}
DAC_CR(dac) = reg;
}
/** @brief Load DAC Data Register.
Loads the appropriate digital to analog converter data register with 12 or 8 bit
data to be converted on a channel. The data can be aligned as follows:
@li right-aligned 8 bit data in bits 0-7
@li right-aligned 12 bit data in bits 0-11
@li left aligned 12 bit data in bits 4-15
@param[in] dac the base address of the DAC. @ref dac_reg_base
@param[in] data uint16_t with appropriate alignment.
@param[in] align enum ::dac_align. Alignment and size.
@param[in] channel uint8_t with DAC mask.
*/
void dac_load_data_buffer_single(uint32_t dac, uint16_t data,
enum dac_align align,
int channel)
{
if (channel == DAC_CHANNEL1) {
switch (align) {
case DAC_ALIGN_RIGHT8:
DAC_DHR8R1(dac) = data;
break;
case DAC_ALIGN_RIGHT12:
DAC_DHR12R1(dac) = data;
break;
case DAC_ALIGN_LEFT12:
DAC_DHR12L1(dac) = data;
break;
default:
break;
}
} else if (channel == DAC_CHANNEL2) {
switch (align) {
case DAC_ALIGN_RIGHT8:
DAC_DHR8R2(dac) = data;
break;
case DAC_ALIGN_RIGHT12:
DAC_DHR12R2(dac) = data;
break;
case DAC_ALIGN_LEFT12:
DAC_DHR12L2(dac) = data;
break;
default:
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 the base address of the DAC. @ref dac_reg_base
@param[in] data1 uint16_t for channel 1 with appropriate alignment.
@param[in] data2 uint16_t for channel 2 with appropriate alignment.
@param[in] align enum ::dac_align. Right or left aligned, and 8 or
12 bit.
*/
void dac_load_data_buffer_dual(uint32_t dac,
uint16_t data1, uint16_t data2,
enum dac_align align)
{
switch (align) {
case DAC_ALIGN_RIGHT8:
DAC_DHR8RD(dac) = ((data1 & 0xFF) | ((data2 & 0xFF) << 8));
break;
case DAC_ALIGN_RIGHT12:
DAC_DHR12RD(dac) = ((data1 & 0xFFF) |
((data2 & 0xFFF) << 16));
break;
case DAC_ALIGN_LEFT12:
DAC_DHR12LD(dac) = ((data1 & 0xFFF) |
((data2 & 0xFFF) << 16));
break;
default:
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 the base address of the DAC. @ref dac_reg_base
@param[in] channel with DAC mask. @ref dac_channel_id
*/
void dac_software_trigger(uint32_t dac, int channel)
{
switch (channel) {
case DAC_CHANNEL1:
DAC_SWTRIGR(dac) |= DAC_SWTRIGR_SWTRIG1;
break;
case DAC_CHANNEL2:
DAC_SWTRIGR(dac) |= DAC_SWTRIGR_SWTRIG2;
break;
case DAC_CHANNEL_BOTH:
DAC_SWTRIGR(dac) |= (DAC_SWTRIGR_SWTRIG1 | DAC_SWTRIGR_SWTRIG2);
break;
default:
break;
}
}
/**@}*/

View File

@@ -0,0 +1,81 @@
/** @addtogroup dac_file DAC peripheral API
* @ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2020 Ben Brewer <ben.brewer@codethink.co.uk>
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2020 Ben Brewer
*
* 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>
/** @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 the base address of the DAC. @ref dac_reg_base
@param[in] channel with DAC mask. @ref dac_channel_id
*/
void dac_buffer_enable(uint32_t dac, int channel)
{
switch (channel) {
case DAC_CHANNEL1:
DAC_CR(dac) &= ~DAC_CR_BOFF1;
break;
case DAC_CHANNEL2:
DAC_CR(dac) &= ~DAC_CR_BOFF2;
break;
case DAC_CHANNEL_BOTH:
DAC_CR(dac) &= ~(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 the base address of the DAC. @ref dac_reg_base
@param[in] channel with DAC mask. @ref dac_channel_id
*/
void dac_buffer_disable(uint32_t dac, int channel)
{
switch (channel) {
case DAC_CHANNEL1:
DAC_CR(dac) |= DAC_CR_BOFF1;
break;
case DAC_CHANNEL2:
DAC_CR(dac) |= DAC_CR_BOFF2;
break;
case DAC_CHANNEL_BOTH:
DAC_CR(dac) |= (DAC_CR_BOFF1 | DAC_CR_BOFF2);
break;
}
}
/**@}*/

View File

@@ -0,0 +1,151 @@
/** @addtogroup dac_file DAC peripheral API
* @ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2020 Ben Brewer <ben.brewer@codethink.co.uk>
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2020 Ben Brewer
*
* 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>
/** @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 the base address of the DAC. @ref dac_reg_base
@param[in] channel with DAC mask. @ref dac_channel_id
*/
void dac_buffer_enable(uint32_t dac, int channel)
{
switch (channel) {
case DAC_CHANNEL1:
DAC_MCR(dac) &= ~DAC_MCR_MODE1_UNBUFFERED;
break;
case DAC_CHANNEL2:
DAC_MCR(dac) &= ~DAC_MCR_MODE2_UNBUFFERED;
break;
case DAC_CHANNEL_BOTH:
DAC_MCR(dac) &= ~(DAC_MCR_MODE1_UNBUFFERED |
DAC_MCR_MODE2_UNBUFFERED);
break;
default:
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 the base address of the DAC. @ref dac_reg_base
@param[in] channel with DAC mask. @ref dac_channel_id
*/
void dac_buffer_disable(uint32_t dac, int channel)
{
switch (channel) {
case DAC_CHANNEL1:
DAC_MCR(dac) |= DAC_MCR_MODE1_UNBUFFERED;
break;
case DAC_CHANNEL2:
DAC_MCR(dac) |= DAC_MCR_MODE2_UNBUFFERED;
break;
case DAC_CHANNEL_BOTH:
DAC_MCR(dac) |= (DAC_MCR_MODE1_UNBUFFERED
| DAC_MCR_MODE2_UNBUFFERED);
break;
default:
break;
}
}
/** @brief DAC Channel Output Mode.
Each DAC channel can be configured in Normal mode or Sample and hold mode. The
output buffer can be enabled to allow a high drive capability. Before enabling
output buffer, the voltage offset needs to be calibrated. This calibration is
performed at the factory (loaded after reset) and can be adjusted by software
during application operation.
@note This must be called before enabling the DAC as the settings will then
become read-only.
@param[in] dac the base address of the DAC. @ref dac_reg_base
@param[in] mode Taken from @ref dac_mode2_sel or @ref dac_mode1_sel or
a logical OR of one of each of these to set both channels simultaneously.
*/
void dac_set_mode(uint32_t dac, uint32_t mode)
{
DAC_MCR(dac) |= mode;
}
/** @brief Check if DAC channel is ready to receive data.
@param[in] dac the base address of the DAC. @ref dac_reg_base
@param[in] channel with DAC mask. @ref dac_channel_id
*/
bool dac_is_ready(uint32_t dac, int channel)
{
uint32_t mask = 0;
if (channel & DAC_CHANNEL1) {
mask |= DAC_SR_DAC1RDY;
}
if (channel & DAC_CHANNEL2) {
mask |= DAC_SR_DAC2RDY;
}
return (DAC_SR(dac) & mask) != 0;
}
/** @brief Wait until DAC channel is ready to receive data.
@param[in] dac the base address of the DAC. @ref dac_reg_base
@param[in] channel with DAC mask. @ref dac_channel_id
*/
void dac_wait_on_ready(uint32_t dac, int channel)
{
while (!dac_is_ready(dac, channel));
}
/** @brief High frequency interface mode selection.
If the AHB frequency of the DAC is above 80MHz then this value needs setting
to an appropriate value.
@param[in] dac the base address of the DAC. @ref dac_reg_base
@param[in] hfsel uint32_t with appropriate HFSEL mask.
*/
void dac_set_high_frequency_mode(uint32_t dac, uint32_t hfsel)
{
uint32_t reg32 = DAC_MCR(dac);
reg32 &= ~(DAC_MCR_HFSEL_MASK << DAC_MCR_HFSEL_SHIFT);
reg32 |= hfsel;
DAC_MCR(dac) = reg32;
}
/**@}*/

View File

@@ -0,0 +1,18 @@
/** @addtogroup dcmi_file DCMI peripheral API
* @ingroup peripheral_apis
* @brief Digital camera interface.
*
* The digital camera is a synchronous parallel interface able to
* receive a high-speed data flow from an external 8-, 10-, 12- or 14-bit
* CMOS camera module.
*
* If the APIs here are insufficient or incomplete, see @ref dcmi_defines
*
* LGPL License Terms @ref lgpl_license
*/
/**@{*/
#include <libopencm3/stm32/dcmi.h>
/**@}*/

View File

@@ -0,0 +1,66 @@
/*
* 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/desig.h>
void desig_get_unique_id_as_string(char *string, unsigned int string_len)
{
int i, len;
uint32_t uid_buf[3];
uint8_t *uid = (uint8_t *)uid_buf;
const char chars[] = "0123456789ABCDEF";
desig_get_unique_id(uid_buf);
/* Each byte produces two characters */
len = (2 * sizeof(uid_buf) < string_len) ?
2 * sizeof(uid_buf) : string_len - 1;
for (i = 0; i < len; i += 2) {
string[i] = chars[(uid[i / 2] >> 4) & 0x0F];
string[i + 1] = chars[(uid[i / 2] >> 0) & 0x0F];
}
string[len] = '\0';
}
void desig_get_unique_id_as_dfu(char *string) {
uint32_t uid_buf[3];
uint8_t *uid = (uint8_t *)uid_buf;
desig_get_unique_id(uid_buf);
uint8_t serial[6];
serial[0] = uid[11];
serial[1] = uid[10] + uid[2];
serial[2] = uid[9];
serial[3] = uid[8] + uid[0];
serial[4] = uid[7];
serial[5] = uid[6];
uint8_t *ser = &serial[0];
uint8_t *end = &serial[6];
const char hex_digit[] = "0123456789ABCDEF";
for (; ser < end; ser++) {
*string++ = hex_digit[(*ser >> 4) & 0x0f];
*string++ = hex_digit[(*ser >> 0) & 0x0f];
}
*string = '\0';
}

View File

@@ -0,0 +1,32 @@
/*
* 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/desig.h>
uint16_t desig_get_flash_size(void)
{
return *((uint32_t*)DESIG_FLASH_SIZE_BASE);
}
void desig_get_unique_id(uint32_t *result)
{
*result++ = DESIG_UNIQUE_ID2;
*result++ = DESIG_UNIQUE_ID1;
*result = DESIG_UNIQUE_ID0;
}

View File

@@ -0,0 +1,33 @@
/** @defgroup dma2d_file DMA2D peripheral API
*
* @ingroup peripheral_apis
*
* @version 1.0.0
*
* This library supports the DMA2D Peripheral in the STM32F4xx and STM32F7xx
* series of ARM Cortex Microcontrollers by ST Microelectronics.
*
* 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/common/dma2d_common_f47.h>
/**@{*/
/**@}*/

View File

@@ -0,0 +1,43 @@
/** @addtogroup dma_file
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2019 Guillaume Revaillot <g.revaillot@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/dma.h>
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Set Request Selection
Set DMA request mapping selection for given channel. Refer to datasheet for channel
request mapping tables.
@param[in] dma DMA controller base address: DMA1 or DMA2
@param[in] channel Channel number: 1-7 for DMA1 or 1-5 for DMA2
@param[in] request DMA request mapping.
*/
void dma_set_channel_request(uint32_t dma, uint8_t channel, uint8_t request)
{
uint32_t reg32 = DMA_CSELR(dma) & ~(DMA_CSELR_CxS_MASK << DMA_CSELR_CxS_SHIFT(channel));
DMA_CSELR(dma) = reg32 | ((DMA_CSELR_CxS_MASK & request) << DMA_CSELR_CxS_SHIFT(channel));
}
/**@}*/

View File

@@ -0,0 +1,810 @@
/** @defgroup dma_file DMA peripheral API
@ingroup peripheral_apis
@brief DMA library for the multi stream controller found in f2/f4/f7 parts.
@author @htmlonly &copy; @endhtmlonly 2012
Ken Sarkies <ksarkies@internode.on.net>
This library supports the DMA Control System in the STM32F2 and STM32F4
series of ARM Cortex Microcontrollers by ST Microelectronics.
Up to two DMA controllers are supported each with 8 streams, and each stream
having up to 8 channels hardware dedicated to various peripheral DMA signals.
DMA transfers can be configured to occur between peripheral and memory in
either direction, and memory to memory. Peripheral to peripheral transfer
is not supported. Circular mode transfers are also supported in transfers
involving a peripheral. An arbiter is provided to resolve priority DMA
requests. Transfers can be made with 8, 16 or 32 bit words.
Each stream has access to a 4 word deep FIFO and can use double buffering
by means of two memory pointers. When using the FIFO it is possible to
configure transfers to occur in indivisible bursts.
It is also possible to select a peripheral instead of the DMA controller to
control the flow of data. This limits the functionality but is useful when the
number of transfers is unknown.
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Ken Sarkies <ksarkies@internode.on.net>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/dma.h>
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Reset
The specified stream is disabled and configuration registers are cleared.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_stream_reset(uint32_t dma, uint8_t stream)
{
/* Disable stream (must be done before register is otherwise changed). */
DMA_SCR(dma, stream) &= ~DMA_SxCR_EN;
/* Reset all config bits. */
DMA_SCR(dma, stream) = 0;
/* Reset data transfer number. */
DMA_SNDTR(dma, stream) = 0;
/* Reset peripheral and memory addresses. */
DMA_SPAR(dma, stream) = 0;
DMA_SM0AR(dma, stream) = 0;
DMA_SM1AR(dma, stream) = 0;
/* This is the default setting */
DMA_SFCR(dma, stream) = 0x21;
/* Reset all stream interrupt flags using the interrupt flag clear register. */
uint32_t mask = DMA_ISR_MASK(stream);
if (stream < 4) {
DMA_LIFCR(dma) |= mask;
} else {
DMA_HIFCR(dma) |= mask;
}
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Clear Interrupt Flag
The interrupt flag for the stream is cleared. More than one interrupt for the
same stream may be cleared by using the bitwise OR of the interrupt flags.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] interrupts unsigned int32. Bitwise OR of interrupt numbers: @ref
dma_if_offset
*/
void dma_clear_interrupt_flags(uint32_t dma, uint8_t stream,
uint32_t interrupts)
{
/* Get offset to interrupt flag location in stream field */
uint32_t flags = (interrupts << DMA_ISR_OFFSET(stream));
/* First four streams are in low register. Flag clear must be set then
* reset.
*/
if (stream < 4) {
DMA_LIFCR(dma) = flags;
} else {
DMA_HIFCR(dma) = flags;
}
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Read Interrupt Flag
The interrupt flag for the stream is returned.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] interrupt unsigned int32. Interrupt number: @ref dma_if_offset
@returns bool interrupt flag is set.
*/
bool dma_get_interrupt_flag(uint32_t dma, uint8_t stream, uint32_t interrupt)
{
/* get offset to interrupt flag location in stream field. Assumes
* stream and interrupt parameters are integers.
*/
uint32_t flag = (interrupt << DMA_ISR_OFFSET(stream));
/* First four streams are in low register */
if (stream < 4) {
return ((DMA_LISR(dma) & flag) > 0);
} else {
return ((DMA_HISR(dma) & flag) > 0);
}
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Enable Transfer Direction
Set peripheral to memory, memory to peripheral or memory to memory. If memory
to memory mode is selected, circular mode and double buffer modes are disabled.
Ensure that these modes are not enabled at a later time.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] direction unsigned int32. Data transfer direction @ref dma_st_dir
*/
void dma_set_transfer_mode(uint32_t dma, uint8_t stream, uint32_t direction)
{
uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_DIR_MASK);
/* Disable circular and double buffer modes if memory to memory
* transfers are in effect. (Direct Mode is automatically disabled by
* hardware)
*/
if (direction == DMA_SxCR_DIR_MEM_TO_MEM) {
reg32 &= ~(DMA_SxCR_CIRC | DMA_SxCR_DBM);
}
DMA_SCR(dma, stream) = (reg32 | direction);
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Set Priority
Stream Priority has four levels: low to very high. This has precedence over the
hardware priority. In the event of equal software priority the lower numbered
stream has priority.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] prio unsigned int32. Priority level @ref dma_st_pri.
*/
void dma_set_priority(uint32_t dma, uint8_t stream, uint32_t prio)
{
DMA_SCR(dma, stream) &= ~(DMA_SxCR_PL_MASK);
DMA_SCR(dma, stream) |= prio;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Set Memory Word Width
Set the memory word width 8 bits, 16 bits, or 32 bits. Refer to datasheet for
alignment information if the source and destination widths do not match.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] mem_size unsigned int32. Memory word width @ref dma_st_memwidth.
*/
void dma_set_memory_size(uint32_t dma, uint8_t stream, uint32_t mem_size)
{
DMA_SCR(dma, stream) &= ~(DMA_SxCR_MSIZE_MASK);
DMA_SCR(dma, stream) |= mem_size;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Set Peripheral Word Width
Set the peripheral word width 8 bits, 16 bits, or 32 bits. Refer to datasheet
for alignment information if the source and destination widths do not match, or
if the peripheral does not support byte or half-word writes.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] peripheral_size unsigned int32. Peripheral word width @ref
dma_st_perwidth.
*/
void dma_set_peripheral_size(uint32_t dma, uint8_t stream,
uint32_t peripheral_size)
{
DMA_SCR(dma, stream) &= ~(DMA_SxCR_PSIZE_MASK);
DMA_SCR(dma, stream) |= peripheral_size;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Enable Memory Increment after Transfer
Following each transfer the current memory address is incremented by
1, 2 or 4 depending on the data size set in @ref dma_set_memory_size. The
value held by the base memory address register is unchanged.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_memory_increment_mode(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) |= DMA_SxCR_MINC;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Memory Increment after Transfer
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_memory_increment_mode(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_MINC;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Variable Sized Peripheral Increment after Transfer
Following each transfer the current peripheral address is incremented by
1, 2 or 4 depending on the data size set in @ref dma_set_peripheral_size. The
value held by the base peripheral address register is unchanged.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_peripheral_increment_mode(uint32_t dma, uint8_t stream)
{
uint32_t reg32 = (DMA_SCR(dma, stream) | DMA_SxCR_PINC);
DMA_SCR(dma, stream) = (reg32 & ~DMA_SxCR_PINCOS);
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Peripheral Increment after Transfer
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_peripheral_increment_mode(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_PINC;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Fixed Sized Peripheral Increment after Transfer
Following each transfer the current peripheral address is incremented by
4 regardless of the data size. The value held by the base peripheral address
register is unchanged.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_fixed_peripheral_increment_mode(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) |= (DMA_SxCR_PINC | DMA_SxCR_PINCOS);
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Enable Memory Circular Mode
After the number of bytes/words to be transferred has been completed, the
original transfer block size, memory and peripheral base addresses are
reloaded and the process repeats.
Ensure that the stream is disabled otherwise the setting will not be changed.
@note This cannot be used with memory to memory mode. It is disabled
automatically if the peripheral is selected as the flow controller.
It is enabled automatically if double buffered mode is selected.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_circular_mode(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) |= DMA_SxCR_CIRC;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Channel Select
Associate an input channel to the stream. Not every channel is allocated to a
hardware DMA request signal. The allocations for each stream are given in the
STM32F4 Reference Manual.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] channel unsigned int8. Channel selection @ref dma_ch_sel
*/
void dma_channel_select(uint32_t dma, uint8_t stream, uint32_t channel)
{
DMA_SCR(dma, stream) |= channel;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Set Memory Burst Configuration
Set the memory burst type to none, 4 8 or 16 word length. This is forced to none
if direct mode is used.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] burst unsigned int8. Memory Burst selection @ref dma_mburst
*/
void dma_set_memory_burst(uint32_t dma, uint8_t stream, uint32_t burst)
{
uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_MBURST_MASK);
DMA_SCR(dma, stream) = (reg32 | burst);
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Set Peripheral Burst Configuration
Set the memory burst type to none, 4 8 or 16 word length. This is forced to none
if direct mode is used.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] burst unsigned int8. Peripheral Burst selection @ref dma_pburst
*/
void dma_set_peripheral_burst(uint32_t dma, uint8_t stream, uint32_t burst)
{
uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_PBURST_MASK);
DMA_SCR(dma, stream) = (reg32 | burst);
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Set Initial Target Memory
In double buffered mode, set the target memory (M0 or M1) to be used for the
first transfer.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] memory unsigned int8. Initial memory pointer to use: 0 or 1
*/
void dma_set_initial_target(uint32_t dma, uint8_t stream, uint8_t memory)
{
uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_CT);
if (memory == 1) {
reg32 |= DMA_SxCR_CT;
}
DMA_SCR(dma, stream) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Read Current Memory Target
In double buffer mode, return the current memory target (M0 or M1). It is
possible to update the memory pointer in the register that is <b> not </b>
currently in use. An attempt to change the register currently in use will cause
the stream to be disabled and the transfer error flag to be set.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@returns unsigned int8. Memory buffer in use: 0 or 1
*/
uint8_t dma_get_target(uint32_t dma, uint8_t stream)
{
if (DMA_SCR(dma, stream) & DMA_SxCR_CT) {
return 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Enable Double Buffer Mode
Double buffer mode is used for memory to/from peripheral transfers only, and in
circular mode which is automatically enabled. Two memory buffers must be
established with pointers stored in the memory pointer registers.
Ensure that the stream is disabled otherwise the setting will not be changed.
@note This cannot be used with memory to memory mode.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_double_buffer_mode(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) |= DMA_SxCR_DBM;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Disable Double Buffer Mode
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_double_buffer_mode(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_DBM;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Set Peripheral Flow Control
Set the peripheral to control DMA flow. Useful when the number of transfers is
unknown. This is forced off when memory to memory mode is selected.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_set_peripheral_flow_control(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) |= DMA_SxCR_PFCTRL;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Set DMA Flow Control
Set the DMA controller to control DMA flow. This is the default.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_set_dma_flow_control(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_PFCTRL;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Enable Interrupt on Transfer Error
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_transfer_error_interrupt(uint32_t dma, uint8_t stream)
{
dma_clear_interrupt_flags(dma, stream, DMA_TEIF);
DMA_SCR(dma, stream) |= DMA_SxCR_TEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Disable Interrupt on Transfer Error
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_transfer_error_interrupt(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_TEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Enable Interrupt on Transfer Half Complete
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_half_transfer_interrupt(uint32_t dma, uint8_t stream)
{
dma_clear_interrupt_flags(dma, stream, DMA_HTIF);
DMA_SCR(dma, stream) |= DMA_SxCR_HTIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Disable Interrupt on Transfer Half Complete
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_half_transfer_interrupt(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_HTIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Enable Interrupt on Transfer Complete
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_transfer_complete_interrupt(uint32_t dma, uint8_t stream)
{
dma_clear_interrupt_flags(dma, stream, DMA_TCIF);
DMA_SCR(dma, stream) |= DMA_SxCR_TCIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Disable Interrupt on Transfer Complete
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_transfer_complete_interrupt(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_TCIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Enable Interrupt on Direct Mode Error
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_direct_mode_error_interrupt(uint32_t dma, uint8_t stream)
{
dma_clear_interrupt_flags(dma, stream, DMA_DMEIF);
DMA_SCR(dma, stream) |= DMA_SxCR_DMEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Disable Interrupt on Direct Mode Error
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_direct_mode_error_interrupt(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_DMEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Enable Interrupt on FIFO Error
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_fifo_error_interrupt(uint32_t dma, uint8_t stream)
{
dma_clear_interrupt_flags(dma, stream, DMA_FEIF);
DMA_SFCR(dma, stream) |= DMA_SxFCR_FEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Disable Interrupt on FIFO Error
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_fifo_error_interrupt(uint32_t dma, uint8_t stream)
{
DMA_SFCR(dma, stream) &= ~DMA_SxFCR_FEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Get FIFO Status
Status of FIFO (empty. full or partial filled states) is returned. This has no
meaning if direct mode is enabled (as the FIFO is not used).
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@returns uint32_t FIFO Status @ref dma_fifo_status
*/
uint32_t dma_fifo_status(uint32_t dma, uint8_t stream)
{
return DMA_SFCR(dma, stream) & DMA_SxFCR_FS_MASK;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Enable Direct Mode
Direct mode is the default. Data is transferred as soon as a DMA request is
received. The FIFO is not used. This must not be set when memory to memory
mode is selected.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_direct_mode(uint32_t dma, uint8_t stream)
{
DMA_SFCR(dma, stream) &= ~DMA_SxFCR_DMDIS;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Enable FIFO Mode
Data is transferred via a FIFO.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_fifo_mode(uint32_t dma, uint8_t stream)
{
DMA_SFCR(dma, stream) |= DMA_SxFCR_DMDIS;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Set FIFO Threshold
This is the filled level at which data is transferred out of the FIFO to the
destination.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] threshold unsigned int8. Threshold setting @ref dma_fifo_thresh
*/
void dma_set_fifo_threshold(uint32_t dma, uint8_t stream, uint32_t threshold)
{
uint32_t reg32 = (DMA_SFCR(dma, stream) & ~DMA_SxFCR_FTH_MASK);
DMA_SFCR(dma, stream) = (reg32 | threshold);
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Enable
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_stream(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) |= DMA_SxCR_EN;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Disable
@note The DMA stream registers retain their values when the stream is disabled.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_stream(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_EN;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Set the Peripheral Address
Set the address of the peripheral register to or from which data is to be
transferred. Refer to the documentation for the specific peripheral.
@note The DMA stream must be disabled before setting this address. This function
has no effect if the stream is enabled.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] address unsigned int32. Peripheral Address.
*/
void dma_set_peripheral_address(uint32_t dma, uint8_t stream, uint32_t address)
{
if (!(DMA_SCR(dma, stream) & DMA_SxCR_EN)) {
DMA_SPAR(dma, stream) = (uint32_t *) address;
}
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Set the Base Memory Address 0
Set the address pointer to the memory location for DMA transfers. The DMA stream
must normally be disabled before setting this address, however it is possible
to change this in double buffer mode when the current target is memory area 1
(see @ref dma_get_target).
This is the default base memory address used in direct mode.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] address unsigned int32. Memory Initial Address.
*/
void dma_set_memory_address(uint32_t dma, uint8_t stream, uint32_t address)
{
uint32_t reg32 = DMA_SCR(dma, stream);
if (!(reg32 & DMA_SxCR_EN) ||
((reg32 & DMA_SxCR_CT) && (reg32 & DMA_SxCR_DBM))) {
DMA_SM0AR(dma, stream) = (uint32_t *) address;
}
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Set the Base Memory Address 1
Set the address pointer to the memory location for DMA transfers. The DMA stream
must normally be disabled before setting this address, however it is possible
to change this in double buffer mode when the current target is memory area 0
(see @ref dma_get_target).
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] address unsigned int32. Memory Initial Address.
*/
void dma_set_memory_address_1(uint32_t dma, uint8_t stream, uint32_t address)
{
uint32_t reg32 = DMA_SCR(dma, stream);
if (!(reg32 & DMA_SxCR_EN) ||
(!(reg32 & DMA_SxCR_CT) && (reg32 & DMA_SxCR_DBM))) {
DMA_SM1AR(dma, stream) = (uint32_t *) address;
}
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Get the Transfer Block Size
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@returns unsigned int16. Number of remaining data words to transfer (65535
maximum).
*/
uint16_t dma_get_number_of_data(uint32_t dma, uint8_t stream)
{
return DMA_SNDTR(dma, stream);
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Set the Transfer Block Size
@note The DMA stream must be disabled before setting this count value. The count
is not changed if the stream is enabled.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] number unsigned int16. Number of data words to transfer (65535
maximum).
*/
void dma_set_number_of_data(uint32_t dma, uint8_t stream, uint16_t number)
{
DMA_SNDTR(dma, stream) = number;
}
/**@}*/

View File

@@ -0,0 +1,451 @@
/** @defgroup dma_file DMA peripheral API
@ingroup peripheral_apis
@brief DMA library for the multi channel controller found in F0/1/3 & L/G parts.
@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
This library supports the DMA Control System in the STM32 series of ARM Cortex
Microcontrollers by ST Microelectronics.
Up to two DMA controllers are supported. 12 DMA channels are allocated 7 to
the first DMA controller and 5 to the second. Each channel is connected to
between 3 and 6 hardware peripheral DMA signals in a logical OR arrangement.
DMA transfers can be configured to occur between peripheral and memory in
any combination including memory to memory. Circular mode transfers are
also supported in transfers involving a peripheral. An arbiter is provided
to resolve priority DMA requests. Transfers can be made with 8, 16 or 32 bit
words.
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/dma.h>
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Reset
The channel is disabled and configuration registers are cleared.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_channel_reset(uint32_t dma, uint8_t channel)
{
/* Disable channel and reset config bits. */
DMA_CCR(dma, channel) = 0;
/* Reset data transfer number. */
DMA_CNDTR(dma, channel) = 0;
/* Reset peripheral address. */
DMA_CPAR(dma, channel) = 0;
/* Reset memory address. */
DMA_CMAR(dma, channel) = 0;
/* Reset interrupt flags. */
DMA_IFCR(dma) |= DMA_IFCR_CIF(channel);
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Clear Interrupt Flag
The interrupt flag for the channel is cleared. More than one interrupt for the
same channel may be cleared by using the logical OR of the interrupt flags.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: @ref dma_ch
@param[in] interrupts unsigned int32. Logical OR of interrupt numbers: @ref
dma_if_offset
*/
void dma_clear_interrupt_flags(uint32_t dma, uint8_t channel,
uint32_t interrupts)
{
/* Get offset to interrupt flag location in channel field */
uint32_t flags = (interrupts << DMA_FLAG_OFFSET(channel));
DMA_IFCR(dma) = flags;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Read Interrupt Flag
The interrupt flag for the channel is returned.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: @ref dma_ch
@param[in] interrupt unsigned int32. Interrupt number: @ref dma_if_offset
@returns bool interrupt flag is set.
*/
bool dma_get_interrupt_flag(uint32_t dma, uint8_t channel, uint32_t interrupt)
{
/* get offset to interrupt flag location in channel field. */
uint32_t flag = (interrupt << DMA_FLAG_OFFSET(channel));
return ((DMA_ISR(dma) & flag) > 0);
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Memory to Memory Transfers
Memory to memory transfers do not require a trigger to activate each transfer.
Transfers begin immediately the channel has been enabled, and proceed without
intervention.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_mem2mem_mode(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_MEM2MEM;
DMA_CCR(dma, channel) &= ~DMA_CCR_CIRC;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Set Priority
Channel Priority has four levels: low to very high. This has precedence over the
hardware priority.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
@param[in] prio unsigned int32. Priority level @ref dma_ch_pri.
*/
void dma_set_priority(uint32_t dma, uint8_t channel, uint32_t prio)
{
DMA_CCR(dma, channel) &= ~(DMA_CCR_PL_MASK);
DMA_CCR(dma, channel) |= prio;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Set Memory Word Width
Set the memory word width 8 bits, 16 bits, or 32 bits. Refer to datasheet for
alignment information if the source and destination widths do not match.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
@param[in] mem_size unsigned int32. Memory word width @ref dma_ch_memwidth.
*/
void dma_set_memory_size(uint32_t dma, uint8_t channel, uint32_t mem_size)
{
DMA_CCR(dma, channel) &= ~(DMA_CCR_MSIZE_MASK);
DMA_CCR(dma, channel) |= mem_size;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Set Peripheral Word Width
Set the peripheral word width 8 bits, 16 bits, or 32 bits. Refer to datasheet
for alignment information if the source and destination widths do not match, or
if the peripheral does not support byte or half-word writes.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
@param[in] peripheral_size unsigned int32. Peripheral word width @ref
dma_ch_perwidth.
*/
void dma_set_peripheral_size(uint32_t dma, uint8_t channel,
uint32_t peripheral_size)
{
DMA_CCR(dma, channel) &= ~(DMA_CCR_PSIZE_MASK);
DMA_CCR(dma, channel) |= peripheral_size;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Memory Increment after Transfer
Following each transfer the current memory address is incremented by
1, 2 or 4 depending on the data size set in @ref dma_set_memory_size. The
value held by the base memory address register is unchanged.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_memory_increment_mode(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_MINC;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Memory Increment after Transfer
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_disable_memory_increment_mode(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_MINC;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Peripheral Increment after Transfer
Following each transfer the current peripheral address is incremented by
1, 2 or 4 depending on the data size set in @ref dma_set_peripheral_size. The
value held by the base peripheral address register is unchanged.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_peripheral_increment_mode(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_PINC;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Peripheral Increment after Transfer
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_disable_peripheral_increment_mode(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_PINC;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Memory Circular Mode
After the number of bytes/words to be transferred has been completed, the
original transfer block size, memory and peripheral base addresses are
reloaded and the process repeats.
@note This cannot be used with memory to memory mode, which is explicitly
disabled here.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_circular_mode(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_CIRC;
DMA_CCR(dma, channel) &= ~DMA_CCR_MEM2MEM;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Transfers from a Peripheral
The data direction is set to read from a peripheral.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_set_read_from_peripheral(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_DIR;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Transfers from Memory
The data direction is set to read from memory.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_set_read_from_memory(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_DIR;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Interrupt on Transfer Error
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_transfer_error_interrupt(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_TEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Interrupt on Transfer Error
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_disable_transfer_error_interrupt(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_TEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Interrupt on Transfer Half Complete
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_half_transfer_interrupt(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_HTIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Interrupt on Transfer Half Complete
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_disable_half_transfer_interrupt(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_HTIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Interrupt on Transfer Complete
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_transfer_complete_interrupt(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_TCIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Interrupt on Transfer Complete
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_disable_transfer_complete_interrupt(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_TCIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_channel(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_EN;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Disable
@note The DMA channel registers retain their values when the channel is
disabled.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_disable_channel(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_EN;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Set the Peripheral Address
Set the address of the peripheral register to or from which data is to be
transferred. Refer to the documentation for the specific peripheral.
@note The DMA channel must be disabled before setting this address. This
function has no effect if the channel is enabled.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
@param[in] address unsigned int32. Peripheral Address.
*/
void dma_set_peripheral_address(uint32_t dma, uint8_t channel, uint32_t address)
{
if (!(DMA_CCR(dma, channel) & DMA_CCR_EN)) {
DMA_CPAR(dma, channel) = (uint32_t) address;
}
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Set the Base Memory Address
@note The DMA channel must be disabled before setting this address. This
function has no effect if the channel is enabled.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
@param[in] address unsigned int32. Memory Initial Address.
*/
void dma_set_memory_address(uint32_t dma, uint8_t channel, uint32_t address)
{
if (!(DMA_CCR(dma, channel) & DMA_CCR_EN)) {
DMA_CMAR(dma, channel) = (uint32_t) address;
}
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Get the Transfer Block Size
@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
@returns unsigned int16. Number of remaining data words to transfer (65535
maximum).
*/
uint16_t dma_get_number_of_data(uint32_t dma, uint8_t channel)
{
return DMA_CNDTR(dma, channel);
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Set the Transfer Block Size
@note The DMA channel must be disabled before setting this count value. The
count is not changed if the channel is enabled.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
@param[in] number unsigned int16. Number of data words to transfer (65535
maximum).
*/
void dma_set_number_of_data(uint32_t dma, uint8_t channel, uint16_t number)
{
DMA_CNDTR(dma, channel) = number;
}
/**@}*/

View File

@@ -0,0 +1,367 @@
/** @addtogroup dmamux_file DMAMUX peripheral API
@ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2019 Guillaume Revaillot <g.revaillot@gmail.com>
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/dmamux.h>
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Reset DMA Channel
Reset DMA Request configuration and interrupt flags for given DMA channel.
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] channel DMA channel number (@ref dma_ch)
*/
void dmamux_reset_dma_channel(uint32_t dmamux, uint8_t channel)
{
DMAMUX_CxCR(dmamux, channel) = 0;
dmamux_clear_dma_request_sync_overrun(dmamux, channel);
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Set DMA Channel Request
Set DMA Request Signal ID (@ref dmamux_cxcr_dmareq_id) for given DMA channel.
Request must be set before enabling and after configuring said DMA channel.
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] channel DMA channel number (@ref dma_ch)
@param[in] request_id DMA request (@ref dmamux_cxcr_dmareq_id)
*/
void dmamux_set_dma_channel_request(uint32_t dmamux, uint8_t channel, uint8_t request_id)
{
uint32_t reg32 = DMAMUX_CxCR(dmamux, channel);
reg32 &= ~(DMAMUX_CxCR_DMAREQ_ID_MASK << DMAMUX_CxCR_DMAREQ_ID_SHIFT);
reg32 |= ((request_id & DMAMUX_CxCR_DMAREQ_ID_MASK) << DMAMUX_CxCR_DMAREQ_ID_SHIFT);
DMAMUX_CxCR(dmamux, channel) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Get DMA Channel Request Selection
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] channel DMA channel number (@ref dma_ch)
@returns DMA request (@ref dmamux_cxcr_dmareq_id)
*/
uint8_t dmamux_get_dma_channel_request(uint32_t dmamux, uint8_t channel)
{
return (DMAMUX_CxCR(dmamux, channel) >> DMAMUX_CxCR_DMAREQ_ID_SHIFT) & DMAMUX_CxCR_DMAREQ_ID_MASK;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Enable DMA Request Event Generation
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] channel DMA channel number (@ref dma_ch)
*/
void dmamux_enable_dma_request_event_generation(uint32_t dmamux, uint8_t channel)
{
DMAMUX_CxCR(dmamux, channel) |= DMAMUX_CxCR_EGE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Disable DMA Request Event Generation
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] channel DMA channel number (@ref dma_ch)
*/
void dmamux_disable_dma_request_event_generation(uint32_t dmamux, uint8_t channel)
{
DMAMUX_CxCR(dmamux, channel) &= ~DMAMUX_CxCR_EGE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Set DMA Request Synchronization Input
Set DMAMUX request synchronization input trigger signal id (@ref dmamux_cxcr_sync_id)
for a given DMA channel.
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] channel DMA channel number (@ref dma_ch)
@param[in] sync_input_id synchronization signal input id (@ref dmamux_cxcr_sync_id)
*/
void dmamux_set_dma_request_sync_input(uint32_t dmamux, uint8_t channel, uint8_t sync_input_id)
{
uint32_t reg32 = DMAMUX_CxCR(dmamux, channel);
reg32 &= ~(DMAMUX_CxCR_SYNC_ID_MASK << DMAMUX_CxCR_SYNC_ID_SHIFT);
reg32 |= ((sync_input_id & DMAMUX_CxCR_SYNC_ID_MASK) << DMAMUX_CxCR_SYNC_ID_SHIFT);
DMAMUX_CxCR(dmamux, channel) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Set DMA Request Synchronization Event Polarity
Set DMAMUX request synchronization input signal polarity (@ref dmamux_cxcr_spol)
for a given DMA channel.
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] channel DMA channel number (@ref dma_ch)
@param[in] polarity synchronization signal input polarity (@ref dmamux_cxcr_spol)
*/
void dmamux_set_dma_request_sync_pol(uint32_t dmamux, uint8_t channel, uint8_t polarity)
{
uint32_t reg32 = DMAMUX_CxCR(dmamux, channel);
reg32 &= ~(DMAMUX_CxCR_SPOL_MASK << DMAMUX_CxCR_SPOL_SHIFT);
reg32 |= ((polarity & DMAMUX_CxCR_SPOL_MASK) << DMAMUX_CxCR_SPOL_SHIFT);
DMAMUX_CxCR(dmamux, channel) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Enable DMA Request Synchronization
Enable DMAMUX request synchronization for a given DMA channel, propagating DMA
request when configured event edge (DMAREQ_CxCR_SPOL) is detected on previously
selected synchronization trigger input id.
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] channel DMA channel number (@ref dma_ch)
*/
void dmamux_enable_dma_request_sync(uint32_t dmamux, uint8_t channel)
{
DMAMUX_CxCR(dmamux, channel) |= DMAMUX_CxCR_SE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Disable DMA Request Synchronization
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] channel DMA channel number (@ref dma_ch)
*/
void dmamux_disable_dma_request_sync(uint32_t dmamux, uint8_t channel)
{
DMAMUX_CxCR(dmamux, channel) &= ~DMAMUX_CxCR_SE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Set DMA Request NBREQ To Forward
Set number of request to forward (minus 1) to the dma controller after a synchronization
event. This must be configured with synchronization and event generation disabled.
@param[in] dmamux DMAMUX Controller base address (@ref dmamux_reg_base)
@param[in] channel DMA Channel Number (@ref dma_ch)
@param[in] nbreq Number of DMA Requests to Forward - minus 1 (0..31)
*/
void dmamux_set_dma_request_sync_nbreq(uint32_t dmamux, uint8_t channel, uint8_t nbreq)
{
uint32_t reg32 = DMAMUX_CxCR(dmamux, channel);
reg32 &= ~(DMAMUX_CxCR_NBREQ_MASK << DMAMUX_CxCR_NBREQ_SHIFT);
reg32 |= ((nbreq & DMAMUX_CxCR_NBREQ_MASK) << DMAMUX_CxCR_NBREQ_SHIFT);
DMAMUX_CxCR(dmamux, channel) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Enable DMA Request Overrun Interrupt
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] channel DMA channel number (@ref dma_ch)
*/
void dmamux_enable_dma_request_sync_overrun_interrupt(uint32_t dmamux, uint8_t channel)
{
DMAMUX_CxCR(dmamux, channel) |= DMAMUX_CxCR_SOIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Disable DMA Request Overrun Interrupt
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] channel DMA channel number (@ref dma_ch)
*/
void dmamux_disable_dma_request_sync_overrun_interrupt(uint32_t dmamux, uint8_t channel)
{
DMAMUX_CxCR(dmamux, channel) &= ~DMAMUX_CxCR_SOIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Get DMA Request Synchronization Overrun Interrupt Flag
Get DMA Request Synchronization Overrun Interrupt for given DMA channel
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] channel DMA channel number (@ref dma_ch)
@returns DMA Channel Synchronization Overrun Interrupt Flag
*/
uint32_t dmamux_get_dma_request_sync_overrun(uint32_t dmamux, uint8_t channel)
{
return DMAMUX_CSR(dmamux) & DMAMUX_CSR_SOF(channel);
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Clear DMA Request Synchronization Overrun Interrupt Flag
Clear DMA Request Synchronization Overrun Interrupt for given DMA channel
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] channel DMA channel number (@ref dma_ch)
*/
void dmamux_clear_dma_request_sync_overrun(uint32_t dmamux, uint8_t channel)
{
DMAMUX_CFR(dmamux) = DMAMUX_CFR_CSOF(channel);
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Reset Request Generator Channel
Reset Request Generator Channel Configuration and interrupt flags.
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] rg_channel Request Generator Channel Number (@ref dmamux_rg_channel)
*/
void dmamux_reset_request_generator_channel(uint32_t dmamux, uint8_t rg_channel)
{
DMAMUX_RGxCR(dmamux, rg_channel) = 0;
dmamux_clear_request_generator_trigger_overrun_interrupt(dmamux, rg_channel);
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Enable Request Generator Channel
Enable Request Generator Channel, Producting DMA Request on input signal trigger.
These Requests are usable by the DMA Request Router.
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] rg_channel Request Generator Channel Number (@ref dmamux_rg_channel)
*/
void dmamux_enable_request_generator(uint32_t dmamux, uint8_t rg_channel)
{
DMAMUX_RGxCR(dmamux, rg_channel) |= DMAMUX_RGxCR_GE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Disable Request Generator Channel
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] rg_channel Request Generator Channel Number (@ref dmamux_rg_channel)
*/
void dmamux_disable_request_generator(uint32_t dmamux, uint8_t rg_channel)
{
DMAMUX_RGxCR(dmamux, rg_channel) &= ~DMAMUX_RGxCR_GE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Set Request Generator Input Trigger Signal
Set DMAMUX Request Generator input signal id (@ref dmamux_rgxcr_sig_id) for given
Request Generator Channel.
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] rg_channel Request Generator Channel Number (@ref dmamux_rg_channel)
@param[in] sig_id Request Generator Channel Input Signal Id (@ref dmamux_rgxcr_sig_id)
*/
void dmamux_set_request_generator_trigger(uint32_t dmamux, uint8_t rg_channel, uint8_t sig_id)
{
uint32_t reg32 = DMAMUX_RGxCR(dmamux, rg_channel);
reg32 &= ~(DMAMUX_RGxCR_SIG_ID_MASK << DMAMUX_RGxCR_SIG_ID_SHIFT);
reg32 |= ((sig_id & DMAMUX_RGxCR_SIG_ID_MASK) << DMAMUX_RGxCR_SIG_ID_SHIFT);
DMAMUX_RGxCR(dmamux, rg_channel) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Set Request Generator Trigger Polarity
Set DMAMUX Request Generator input signal polarity (@ref dmamux_rgxcr_gpol).
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] rg_channel Request Generator Channel Number (@ref dmamux_rg_channel)
@param[in] polarity Trigger signal input polarity (@ref dmamux_rgxcr_gpol)
*/
void dmamux_set_request_generator_trigger_pol(uint32_t dmamux, uint8_t rg_channel, uint8_t polarity)
{
uint32_t reg32 = DMAMUX_RGxCR(dmamux, rg_channel);
reg32 &= ~(DMAMUX_RGxCR_GPOL_MASK << DMAMUX_RGxCR_GPOL_SHIFT);
reg32 |= ((polarity & DMAMUX_RGxCR_GPOL_MASK) << DMAMUX_RGxCR_GPOL_SHIFT);
DMAMUX_RGxCR(dmamux, rg_channel) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Set Request Generator Trigger GNBREQ
Set number of request to generate (minus 1). This must be configured while
given Request Generator is disabled.
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] rg_channel Request Generator Channel Number (@ref dmamux_rg_channel)
@param[in] gnbreq Number of DMA Requests to Generate - minus 1 (0..31).
*/
void dmamux_set_request_generator_trigger_gnbreq(uint32_t dmamux, uint8_t rg_channel, uint8_t gnbreq)
{
uint32_t reg32 = DMAMUX_RGxCR(dmamux, rg_channel);
reg32 &= ~(DMAMUX_RGxCR_GNBREQ_MASK << DMAMUX_RGxCR_GNBREQ_SHIFT);
reg32 |= ((gnbreq & DMAMUX_RGxCR_GNBREQ_MASK) << DMAMUX_RGxCR_GNBREQ_SHIFT);
DMAMUX_RGxCR(dmamux, rg_channel) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Enable Request Generator Trigger Overrun Interrupt
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] rg_channel Request Generator Channel Number (@ref dmamux_rg_channel)
*/
void dmamux_enable_request_generator_trigger_overrun_interrupt(uint32_t dmamux, uint8_t rg_channel)
{
DMAMUX_RGxCR(dmamux, rg_channel) |= DMAMUX_RGxCR_OIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Disable Request Generator Trigger Overrun Interrupt
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] rg_channel Request Generator Channel Number (@ref dmamux_rg_channel)
*/
void dmamux_disable_request_generator_trigger_overrun_interrupt(uint32_t dmamux, uint8_t rg_channel)
{
DMAMUX_RGxCR(dmamux, rg_channel) &= ~DMAMUX_RGxCR_OIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Get Request Generator Trigger Overrun Interrupt Flag
Get DMA Request Synchronization Overrun Interrupt Flag for given Request Generator Channel
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] rg_channel Request Generator Channel Number (@ref dmamux_rg_channel)
@returns Request Generator Channel Trigger Overrun Interrupt Flag
*/
uint32_t dmamux_get_request_generator_trigger_overrun_interrupt(uint32_t dmamux, uint8_t rg_channel)
{
return DMAMUX_RGSR(dmamux) & DMAMUX_RGSR_OF(rg_channel);
}
/*---------------------------------------------------------------------------*/
/** @brief DMAMUX Clear Request Generator Trigger Overrun Interrupt Flag
Clear DMA Request Synchronization Overrun Interrupt Flag for given Request Generator
Channel
@param[in] dmamux DMAMUX controller base address (@ref dmamux_reg_base)
@param[in] rg_channel Request Generator Channel Number (@ref dmamux_rg_channel)
*/
void dmamux_clear_request_generator_trigger_overrun_interrupt(uint32_t dmamux, uint8_t rg_channel)
{
DMAMUX_RGCFR(dmamux) = DMAMUX_RGCFR_COF(rg_channel);
}
/**@}*/

View File

@@ -0,0 +1,34 @@
/** @defgroup dsi_file DSI peripheral API
*
* @ingroup peripheral_apis
*
* @version 1.0.0
*
* This library supports the Display Serial Interface Host and Wrapper in
* the STM32F4xx and STM32F7xx series of ARM Cortex Microcontrollers by
* ST Microelectronics.
*
* 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/common/dsi_common_f47.h>
/**@{*/
/**@}*/

View File

@@ -0,0 +1,180 @@
/** @addtogroup exti_file EXTI peripheral API
* @ingroup peripheral_apis
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* This provides the code for the "next gen" EXTI block provided in F2/F4/F7/L1
* devices. (differences only in the source selection)
*/
/**@{*/
#include <libopencm3/stm32/exti.h>
#include <libopencm3/stm32/gpio.h>
#if defined(EXTI_EXTICR)
#define EXTICR_SELECTION_FIELDSIZE EXTI_EXTICR_FIELDSIZE
#define EXTICR_SELECTION_REG(x) EXTI_EXTICR(x)
#elif defined(AFIO_EXTICR)
#define EXTICR_SELECTION_FIELDSIZE AFIO_EXTICR_FIELDSIZE
#define EXTICR_SELECTION_REG(x) AFIO_EXTICR(x)
#else
#include <libopencm3/stm32/syscfg.h>
#define EXTICR_SELECTION_FIELDSIZE SYSCFG_EXTICR_FIELDSIZE
#define EXTICR_SELECTION_REG(x) SYSCFG_EXTICR(x)
#endif
void exti_set_trigger(uint32_t extis, enum exti_trigger_type trig)
{
switch (trig) {
case EXTI_TRIGGER_RISING:
EXTI_RTSR |= extis;
EXTI_FTSR &= ~extis;
break;
case EXTI_TRIGGER_FALLING:
EXTI_RTSR &= ~extis;
EXTI_FTSR |= extis;
break;
case EXTI_TRIGGER_BOTH:
EXTI_RTSR |= extis;
EXTI_FTSR |= extis;
break;
}
}
void exti_enable_request(uint32_t extis)
{
/* Enable interrupts. */
EXTI_IMR |= extis;
/* Enable events. */
EXTI_EMR |= extis;
}
void exti_disable_request(uint32_t extis)
{
/* Disable interrupts. */
EXTI_IMR &= ~extis;
/* Disable events. */
EXTI_EMR &= ~extis;
}
/*
* Reset the interrupt request by writing a 1 to the corresponding
* pending bit register.
*/
void exti_reset_request(uint32_t extis)
{
#if defined(EXTI_RPR1) && defined(EXTI_FPR1)
EXTI_RPR1 = extis;
EXTI_FPR1 = extis;
#else
EXTI_PR = extis;
#endif
}
/*
* Check the flag of a given EXTI interrupt.
* */
uint32_t exti_get_flag_status(uint32_t exti)
{
#if defined(EXTI_RPR1) && defined(EXTI_FPR1)
return (EXTI_RPR1 & exti) | (EXTI_FPR1 & exti);
#else
return EXTI_PR & exti;
#endif
}
/*
* Remap an external interrupt line to the corresponding pin on the
* specified GPIO port.
*
* TODO: This could be rewritten in fewer lines of code.
*/
void exti_select_source(uint32_t exti, uint32_t gpioport)
{
uint32_t line;
for (line = 0; line < 16; line++) {
if (!(exti & (1 << line))) {
continue;
}
uint32_t bits = 0;
switch (gpioport) {
case GPIOA:
bits = 0;
break;
case GPIOB:
bits = 1;
break;
case GPIOC:
bits = 2;
break;
case GPIOD:
bits = 3;
break;
#if defined(GPIOE) && defined(GPIO_PORT_E_BASE)
case GPIOE:
bits = 4;
break;
#endif
#if defined(GPIOF) && defined(GPIO_PORT_F_BASE)
case GPIOF:
bits = 5;
break;
#endif
#if defined(GPIOG) && defined(GPIO_PORT_G_BASE)
case GPIOG:
bits = 6;
break;
#endif
#if defined(GPIOH) && defined(GPIO_PORT_H_BASE)
case GPIOH:
bits = 7;
break;
#endif
#if defined(GPIOI) && defined(GPIO_PORT_I_BASE)
case GPIOI:
bits = 8;
break;
#endif
#if defined(GPIOJ) && defined(GPIO_PORT_J_BASE)
case GPIOJ:
bits = 9;
break;
#endif
#if defined(GPIOK) && defined(GPIO_PORT_K_BASE)
case GPIOK:
bits = 10;
break;
#endif
}
uint8_t shift = (uint8_t)(EXTICR_SELECTION_FIELDSIZE * (line % 4));
uint32_t mask = ((1 << EXTICR_SELECTION_FIELDSIZE) - 1) << shift;
uint32_t reg = line / 4;
EXTICR_SELECTION_REG(reg) = (EXTICR_SELECTION_REG(reg) & ~mask) | (bits << shift);
};
}
/**@}*/

View File

@@ -0,0 +1,71 @@
/** @addtogroup exti_file EXTI peripheral API
* @ingroup peripheral_apis
*
* @author @htmlonly &copy; @endhtmlonly 2019 Guillaume Revaillot <g.revaillot@gmail.com>
*
* @date 10 January 2019
*
* 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/exti.h>
/* @brief Get the rising edge interrupt requestf flag of a given EXTI interrupt.
*
* @param[in] exti unsigned int32 Exti line.
*
* */
uint32_t exti_get_rising_flag_status(uint32_t exti)
{
return (EXTI_RPR1 & exti);
}
/* @brief Get the rising edge interrupt request flag of a given EXTI interrupt.
*
* @param[in] exti unsigned int32 Exti line.
*
* */
uint32_t exti_get_falling_flag_status(uint32_t exti)
{
return (EXTI_FPR1 & exti);
}
/* @brief Resets the rising edge interrupt request pending flag of a given EXTI interrupt.
*
* @param[in] exti unsigned int32 Exti line.
*
* */
void exti_reset_rising_request(uint32_t extis)
{
EXTI_RPR1 = extis;
}
/* @brief Resets the falling edge interrupt request pending flag of a given EXTI interrupt.
*
* @param[in] exti unsigned int32 Exti line.
*
* */
void exti_reset_falling_request(uint32_t extis)
{
EXTI_FPR1 = extis;
}
/**@}*/

View File

@@ -0,0 +1,699 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2021 Eduard Drusa <ventyl86 at netkosice dot sk>
*
* 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/fdcan.h>
#include <libopencm3/stm32/rcc.h>
#include <stddef.h>
/* --- FD-CAN internal functions -------------------------------------------- */
/** Routine implementing FDCAN_CCCR's INIT bit manipulation.
*
* This routine will change INIT bit and wait for it to actually
* change its value. If change won't happen before timeout,
* error is signalized. If INIT bit already has value which
* should be set, this function will return immediately.
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @param [in] set new value of INIT, true means set
* @param [in] timeout Amount of busyloop cycles, function will wait for FDCAN
* to switch it's state. If set to 0, then function returns immediately.
* @returns FDCAN_E_OK on success, FDCAN_E_TIMEOUT if INIT bit value
* didn't change before timeout has expired.
*/
int fdcan_cccr_init_cfg(uint32_t canport, bool set, uint32_t timeout)
{
uint32_t expected;
uint32_t wait_ack;
if (set) {
if ((FDCAN_CCCR(canport) & FDCAN_CCCR_INIT) == FDCAN_CCCR_INIT) {
/* Already there, sir */
return FDCAN_E_OK;
}
FDCAN_CCCR(canport) |= FDCAN_CCCR_INIT;
expected = FDCAN_CCCR_INIT;
} else {
if ((FDCAN_CCCR(canport) & FDCAN_CCCR_INIT) == 0) {
/* Already there, sir */
return FDCAN_E_OK;
}
FDCAN_CCCR(canport) &= ~FDCAN_CCCR_INIT;
expected = 0;
}
/* Wait, until INIT bit is acknowledged */
wait_ack = timeout;
while ((wait_ack--) &&
((FDCAN_CCCR(canport) & FDCAN_CCCR_INIT) == expected));
if ((FDCAN_CCCR(canport) & FDCAN_CCCR_INIT) == expected) {
return FDCAN_E_OK;
} else {
return FDCAN_E_TIMEOUT;
}
}
/** Return ID of next free Tx buffer.
*
* Examines transmit buffer allocation in message RAM
* and returns ID of buffer, which is free.
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @returns Non-negative number ID of Tx buffer which is free,
* or FDCAN_E_BUSY if no Tx buffer is available
*/
static int fdcan_get_free_txbuf(uint32_t canport)
{
if ((FDCAN_TXBRP(canport) & FDCAN_TXBRP_TRP0) == 0) {
return 0;
} else if ((FDCAN_TXBRP(canport) & FDCAN_TXBRP_TRP1) == 0) {
return 1;
} else if ((FDCAN_TXBRP(canport) & FDCAN_TXBRP_TRP2) == 0) {
return 2;
}
return FDCAN_E_BUSY;
}
/** Returns fill state and next available get index from receive FIFO.
*
* Examines FDCAN receive FIFO and returns fill status of FIFO and ID of
* next message available for reading. If fill status is 0 (FIFO is empty),
* then get index is undefined.
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @param [in] fifo_id ID of fifo queried (currently 0 or 1)
* @param [out] get_index Address of buffer where next get index will be stored
* @param [out] pending_frames Address of buffer where amount of pending frame will be stored.
*/
static void fdcan_get_fill_rxfifo(uint32_t canport, uint8_t fifo_id, unsigned *get_index,
unsigned *pending_frames)
{
*get_index = (FDCAN_RXFIS(canport, fifo_id) >> FDCAN_RXFIFO_GI_SHIFT)
& FDCAN_RXFIFO_GI_MASK;
*pending_frames = (FDCAN_RXFIS(canport, fifo_id) >> FDCAN_RXFIFO_FL_SHIFT)
& FDCAN_RXFIFO_FL_MASK;
}
/** Returns standard filter start address in message RAM
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @returns Base address of standard filter configuration block.
*/
struct fdcan_standard_filter *fdcan_get_flssa_addr(uint32_t canport)
{
struct fdcan_standard_filter *lfssa = (struct fdcan_standard_filter *)
(CAN_MSG_BASE + FDCAN_LFSSA_OFFSET(canport));
return lfssa;
}
/** Returns extended filter start address in message RAM
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @returns Base address of extended filter configuration block.
*/
struct fdcan_extended_filter *fdcan_get_flesa_addr(uint32_t canport)
{
struct fdcan_extended_filter *lfesa = (struct fdcan_extended_filter *)
(CAN_MSG_BASE + FDCAN_LFESA_OFFSET(canport));
return lfesa;
}
/** Returns a pointer to an RX FIFO element in message RAM
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @param [in] fifo_id ID of FIFO whose address is requested
* @param [in] element_id the element number in the fifo we're requesting
* @returns a pointer to the individual element in the message ram
*/
struct fdcan_rx_fifo_element *fdcan_get_rxfifo_addr(uint32_t canport,
unsigned fifo_id, unsigned element_id)
{
struct fdcan_rx_fifo_element *rxfifo = (struct fdcan_rx_fifo_element *)
(CAN_MSG_BASE + FDCAN_RXFIFO_OFFSET(canport, fifo_id)
+ (element_id * fdcan_get_fifo_element_size(canport, fifo_id))
);
return rxfifo;
}
/** Returns transmit event start address in message RAM
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @returns Base address of transmit event block.
*/
struct fdcan_tx_event_element *fdcan_get_txevt_addr(uint32_t canport)
{
struct fdcan_tx_event_element *rxfifo = (struct fdcan_tx_event_element *)
(CAN_MSG_BASE + FDCAN_TXEVT_OFFSET(canport));
return rxfifo;
}
/** Returns a pointer to an TX FIFO element in message RAM
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @param [in] element_id the element number in the fifo we're requesting
* @returns a pointer to the individual element in the message ram
*/
struct fdcan_tx_buffer_element *fdcan_get_txbuf_addr(uint32_t canport, unsigned element_id)
{
struct fdcan_tx_buffer_element *rxfifo = (struct fdcan_tx_buffer_element *)
(CAN_MSG_BASE + FDCAN_TXBUF_OFFSET(canport)
+ (element_id * fdcan_get_txbuf_element_size(canport))
);
return rxfifo;
}
/** Converts frame length to DLC value.
*
* Works for both CAN and FDCAN frame lengths. If length
* is invalid value, then returns 0xFF.
*
* @param [in] length intended frame payload length in bytes
* @returns DLC value representing lengths or 0xFF if length cannot
* be encoded into DLC format (applies only to FDCAN frame lengths)
*/
uint32_t fdcan_length_to_dlc(uint8_t length)
{
if (length <= 8) {
return length;
} else if (length <= 24) {
if ((length % 4) != 0) {
return 0xFF;
}
return 8 + ((length - 8) / 4);
} else {
if ((length % 16) != 0) {
return 0xFF;
}
return 11 + (length / 16);
}
}
/** Converts DLC value into frame payload length.
*
* Works for both CAN and FDCAN DLC values.
*
* @param [in] dlc DLC value
* @returns data payload length in bytes
*/
uint8_t fdcan_dlc_to_length(uint32_t dlc)
{
if (dlc <= 8) {
return dlc;
} else if (dlc <= 12) {
return 8 + ((dlc - 8) * 4);
} else {
return 16 + ((dlc - 12) * 16);
}
}
/* --- FD-CAN functions ----------------------------------------------------- */
/** @ingroup fdcan_file */
/**@{
* */
/** Put FDCAN block into INIT mode for setup
*
* Initialize the selected CAN peripheral block. This function will switch CAN block
* into initialization mode. CAN block is then left in initialization mode in order to
* perform setup, which can't be adjusted once FDCAN block is started. It is mandatory
* to call at least @ref fdcan_set_can function to configure basic timing values for
* CAN 2.0 operation. Functions which only have effect, if FDCAN block is in INIT mode
* are:
* * @ref fdcan_set_can
* * @ref fdcan_set_fdcan
* * @ref fdcan_init_filter
* * @ref fdcan_set_test
*
* You can check if FDCAN block is in INIT mode or it is started using
* @ref fdcan_get_init_state.
*
* @param[in] canport CAN register base address. See @ref fdcan_block.
* @param [in] timeout Amount of empty busy loops, which routine should wait for FDCAN
* confirming that it entered INIT mode. If set to 0, function will
* return immediately.
* @returns Operation error status. See @ref fdcan_error.
*/
int fdcan_init(uint32_t canport, uint32_t timeout)
{
if (fdcan_cccr_init_cfg(canport, true, timeout) != 0) {
return FDCAN_E_TIMEOUT;
}
FDCAN_CCCR(canport) |= FDCAN_CCCR_CCE;
return FDCAN_E_OK;
}
/** Set essential FDCAN block parameters for plain CAN operation
*
* Allows configuration of prescalers and essential transmit and FIFO behavior
* used during transmission in plain CAN 2.0 mode. In this mode FDCAN frame format
* is not available nor is possible to use fast bitrates.
* This function does neither enable FD-CAN mode after reset nor disable it
* after re-entering INIT mode of previously configured block. Timing values set
* here are valid for both arbitration phase of all frames and for data phase of
* both CAN and FDCAN frames, which don't use bitrate switching. This function can
* only be called after FDCAN block has been switched into INIT mode.
* It is possible to receive FDCAN frames even if FDCAN block is configured only using
* this function as long as bitrate switching is not used.
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @param [in] auto_retry_disable Disable automatic frame retransmission on error
* @param [in] rx_fifo_locked Enable FIFO locked mode. Upon FIFO overflow all received
* messages are discarded.
* @param [in] tx_queue_mode Enable transmission queue mode. Otherwise transmission
* works in FIFO mode.
* @param [in] silent Enable silent mode. Transmitter stays recessive all the time.
* @param [in] n_sjw Resynchronization time quanta jump width
* @param [in] n_ts1 Time segment 1 time quanta
* @param [in] n_ts2 Time segment 2 time quanta
* @param [in] n_br_presc Arbitration phase / CAN mode bitrate prescaler
*/
void fdcan_set_can(uint32_t canport, bool auto_retry_disable, bool rx_fifo_locked,
bool tx_queue_mode, bool silent, uint32_t n_sjw, uint32_t n_ts1, uint32_t n_ts2,
uint32_t n_br_presc)
{
FDCAN_NBTP(canport) = (n_sjw << FDCAN_NBTP_NSJW_SHIFT)
| (n_ts1 << FDCAN_NBTP_NTSEG1_SHIFT)
| (n_ts2 << FDCAN_NBTP_NTSEG2_SHIFT)
| (n_br_presc << FDCAN_NBTP_NBRP_SHIFT);
if (tx_queue_mode) {
FDCAN_TXBC(canport) |= FDCAN_TXBC_TFQM;
} else {
FDCAN_TXBC(canport) &= ~FDCAN_TXBC_TFQM;
}
if (auto_retry_disable) {
FDCAN_CCCR(canport) |= FDCAN_CCCR_DAR;
} else {
FDCAN_CCCR(canport) &= ~FDCAN_CCCR_DAR;
}
if (silent) {
FDCAN_CCCR(canport) |= FDCAN_CCCR_MON;
} else {
FDCAN_CCCR(canport) &= ~FDCAN_CCCR_MON;
}
fdcan_set_fifo_locked_mode(canport, rx_fifo_locked);
}
/** Set FDCAN block parameters for FDCAN transmission
*
* Enables and configures parameters related to FDCAN transmission. This function
* allows configuration of bitrate switching, FDCAN frame format and fast mode
* timing. This function can only be called if FDCAN block is in INIT mode.
* It is safe to call this function on previously configured block in order
* to enable/disable/change FDCAN mode parameters. Non-FDCAN parameters won't
* be affected.
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @param [in] brs_enable Enable FDCAN bitrate switching for fast mode operation
* @param [in] fd_op_enable Enable transmission of FDCAN-formatted frames
* @param [in] f_sjw Resynchronization time quanta jump width in fast mode
* @param [in] f_ts1 Time segment 1 time quanta in fast mode
* @param [in] f_ts2 Time segment 2 time quanta in fast mode
* @param [in] f_br_presc Fast mode operation bitrate prescaler
*/
void fdcan_set_fdcan(uint32_t canport, bool brs_enable, bool fd_op_enable,
uint32_t f_sjw, uint32_t f_ts1, uint32_t f_ts2, uint32_t f_br_presc)
{
FDCAN_DBTP(canport) = (f_sjw << FDCAN_DBTP_DSJW_SHIFT)
| (f_ts1 << FDCAN_DBTP_DTSEG1_SHIFT)
| (f_ts2 << FDCAN_DBTP_DTSEG2_SHIFT)
| (f_br_presc << FDCAN_DBTP_DBRP_SHIFT);
if (fd_op_enable) {
FDCAN_CCCR(canport) |= FDCAN_CCCR_FDOE;
} else {
FDCAN_CCCR(canport) &= ~FDCAN_CCCR_FDOE;
}
if (brs_enable) {
FDCAN_CCCR(canport) |= FDCAN_CCCR_BRSE;
} else {
FDCAN_CCCR(canport) &= ~FDCAN_CCCR_BRSE;
}
}
/** Set FDCAN block testing features.
*
* Configures self-test functions of FDCAN block. It is safe to call
* this function on fully configured interface. This function can
* only be called after FDCAN block is put into INIT mode.
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @param [in] testing Enables testing mode of FDCAN block
* @param [in] loopback Enables transmission loopback
*/
void fdcan_set_test(uint32_t canport, bool testing, bool loopback)
{
if (testing) {
FDCAN_CCCR(canport) |= FDCAN_CCCR_TEST;
if (loopback) {
FDCAN_TEST(canport) |= FDCAN_TEST_LBCK;
} else {
FDCAN_TEST(canport) &= ~FDCAN_TEST_LBCK;
}
} else {
FDCAN_CCCR(canport) &= ~FDCAN_CCCR_TEST;
/* FDCAN_TEST is automatically reset to default values by
* FDCAN at this point */
}
}
/** Return current FDCAN block operation state.
*
* This function effectively returns value of FDCAN_CCCR's INIT bit.
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @returns 1 if FDCAN block is in INIT mode, 0 if it is already started.
*/
int fdcan_get_init_state(uint32_t canport)
{
return ((FDCAN_CCCR(canport) & FDCAN_CCCR_INIT) == FDCAN_CCCR_INIT);
}
/** Configure filter rule for standard ID frames.
*
* Sets up filter rule for frames having standard ID. Each FDCAN block can
* have its own set of filtering rules. It is only possible to configure as
* many filters as was configured previously using @ref fdcan_init_filter.
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @param [in] nr number of filter to be configured
* @param [in] id_list_mode Mode in which id1 and id2 are used to match the rule.
* See @ref fdcan_sft.
* @param [in] id1 standard ID for matching. Used as exact value, lower bound or bit
* pattern depending on matching mode selected
* @param [in] id2 standard ID or bitmask. Used as exact value, upper bound or bit mask
* depending on matching mode selected
* @param [in] action Action performed if filtering rule matches frame ID.
* See @ref fdcan_sfec.
*/
void fdcan_set_std_filter(uint32_t canport, uint32_t nr,
uint8_t id_list_mode, uint32_t id1, uint32_t id2,
uint8_t action)
{
struct fdcan_standard_filter *lfssa = fdcan_get_flssa_addr(canport);
/* id_list_mode and action are passed unguarded. Simply use
* defines and it will be OK. id1 and id2 are masked for
* correct size, because it is way too simple to pass ID
* larger than 11 bits unintentionally. It then leads to all
* kind of extremely weird errors while excessive ID bits
* overflow into flags. This tends to be extremely time
* consuming to debug.
*/
lfssa[nr].type_id1_conf_id2 =
(id_list_mode << FDCAN_SFT_SHIFT)
| (action << FDCAN_SFEC_SHIFT)
| ((id1 & FDCAN_SFID1_MASK) << FDCAN_SFID1_SHIFT)
| ((id2 & FDCAN_SFID2_MASK) << FDCAN_SFID2_SHIFT);
return;
}
/** Configure filter rule for extended ID frames.
*
* Sets up filter rule for frames having extended ID. Each FDCAN block can
* have its own set of filtering rules. It is only possible to configure as
* many filters as was configured previously using @ref fdcan_init_filter.
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @param [in] nr number of filter to be configured
* @param [in] id_list_mode mode in which id1 and id2 are used to match the rule.
* See @ref fdcan_eft.
* @param [in] id1 extended ID for matching. Used as exact value, lower bound or bit
* pattern depending on matching mode selected
* @param [in] id2 extended ID or bitmask. Used as exact value, upper bound or bit mask
* depending on matching mode selected
* @param [in] action Action performed if filtering rule matches frame ID.
* See @ref fdcan_efec.
*/
void fdcan_set_ext_filter(uint32_t canport, uint32_t nr,
uint8_t id_list_mode, uint32_t id1, uint32_t id2,
uint8_t action)
{
struct fdcan_extended_filter *lfesa = fdcan_get_flesa_addr(canport);
lfesa[nr].conf_id1 =
(action << FDCAN_EFEC_SHIFT)
| ((id1 & FDCAN_EFID1_MASK) << FDCAN_EFID1_SHIFT);
lfesa[nr].type_id2 =
(id_list_mode << FDCAN_EFT_SHIFT)
| ((id2 & FDCAN_EFID2_MASK) << FDCAN_EFID2_SHIFT);
}
/** Transmit Message using FDCAN
*
* @param [in] canport CAN block register base. See @ref fdcan_block.
* @param [in] id Message ID
* @param [in] ext Extended message ID
* @param [in] rtr Request transmit
* @param [in] fdcan_fmt Use FDCAN format
* @param [in] btr_switch Switch bitrate for data portion of frame
* @param [in] length Message payload length. Must be valid CAN or FDCAN frame length
* @param [in] data Message payload data
* @returns int 0, 1 or 2 on success and depending on which outgoing mailbox got
* selected. Otherwise returns error code. For error codes, see @ref fdcan_error.
*/
int fdcan_transmit(uint32_t canport, uint32_t id, bool ext, bool rtr,
bool fdcan_fmt, bool btr_switch, uint8_t length, const uint8_t *data)
{
int mailbox;
uint32_t dlc, flags = 0;
mailbox = fdcan_get_free_txbuf(canport);
if (mailbox == FDCAN_E_BUSY) {
return mailbox;
}
struct fdcan_tx_buffer_element *tx_buffer = fdcan_get_txbuf_addr(canport, mailbox);
/* Early check: if FDCAN message lentgh is > 8, it must be
* a multiple of 4 *and* fdcan format must be enabled.
*/
dlc = fdcan_length_to_dlc(length);
if (dlc == 0xFF) {
return FDCAN_E_INVALID;
}
if (ext) {
tx_buffer->identifier_flags = FDCAN_FIFO_XTD
| ((id & FDCAN_FIFO_EID_MASK) << FDCAN_FIFO_EID_SHIFT);
} else {
tx_buffer->identifier_flags =
(id & FDCAN_FIFO_SID_MASK) << FDCAN_FIFO_SID_SHIFT;
}
if (rtr) {
tx_buffer->identifier_flags |= FDCAN_FIFO_RTR;
}
if (fdcan_fmt) {
flags |= FDCAN_FIFO_FDF;
}
if (btr_switch) {
flags |= FDCAN_FIFO_BRS;
}
tx_buffer->evt_fmt_dlc_res =
(dlc << FDCAN_FIFO_DLC_SHIFT) | flags;
for (int q = 0; q < length; q += 4) {
tx_buffer->data[q / 4] = *((uint32_t *) &data[q]);
}
FDCAN_TXBAR(canport) |= 1 << mailbox;
return mailbox;
}
/** Receive Message from FDCAN FIFO
*
* Reads one message from receive FIFO. Returns message ID, type of ID, message length
* and message payload. It is mandatory to provide valid pointers to suitably sized buffers
* for these outputs. Additionally, it is optinally possible to provide non-zero pointer to
* obtain filter identification, request of transmission flag and message timestamp.
* If pointers provided for optional outputs are NULL, then no information is returned
* for given pointer.
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block
* @param [in] fifo_id FIFO id.
* @param [in] release Release the FIFO automatically after copying data out
* @param [out] id Returned message ID. Mandatory.
* @param [out] ext Returned type of the message ID (true if extended). Mandatory.
* @param [out] rtr Returnes flag if request of transmission was requested. Optional.
* @param [out] fmi Returned ID of the filter which matched this frame. Optional.
* @param [out] length Length of message payload in bytes. Mandatory.
* @param [out] data Buffer for storage of message payload data. Mandatory.
* @param [out] timestamp Returned timestamp of received frame. Optional.
* @returns Operation error status. See @ref fdcan_error.
*/
int fdcan_receive(uint32_t canport, uint8_t fifo_id, bool release, uint32_t *id,
bool *ext, bool *rtr, uint8_t *fmi, uint8_t *length,
uint8_t *data, uint16_t *timestamp)
{
unsigned pending_frames, get_index, dlc, len;
fdcan_get_fill_rxfifo(canport, fifo_id, &get_index, &pending_frames);
if (pending_frames == 0) {
return FDCAN_E_NOTAVAIL;
}
const struct fdcan_rx_fifo_element *fifo = fdcan_get_rxfifo_addr(canport,
fifo_id, get_index);
dlc = (fifo->filt_fmt_dlc_ts >> FDCAN_FIFO_DLC_SHIFT)
& FDCAN_FIFO_DLC_MASK;
len = fdcan_dlc_to_length(dlc);
*length = len;
if ((fifo->identifier_flags & FDCAN_FIFO_XTD) == FDCAN_FIFO_XTD) {
*ext = true;
*id = (fifo->identifier_flags >> FDCAN_FIFO_EID_SHIFT)
& FDCAN_FIFO_EID_MASK;
} else {
*ext = false;
*id = (fifo->identifier_flags >> FDCAN_FIFO_SID_SHIFT)
& FDCAN_FIFO_SID_MASK;
}
if (timestamp) {
*timestamp = (uint16_t) (fifo->filt_fmt_dlc_ts >> FDCAN_FIFO_RXTS_SHIFT)
& FDCAN_FIFO_RXTS_MASK;
}
if (fmi) {
*fmi = (uint8_t) (fifo->filt_fmt_dlc_ts >> FDCAN_FIFO_MM_SHIFT)
& FDCAN_FIFO_MM_MASK;
}
if (rtr) {
*rtr = ((fifo->identifier_flags & FDCAN_FIFO_RTR) == FDCAN_FIFO_RTR);
}
for (unsigned int q = 0; q < len; q += 4) {
*((uint32_t *) &data[q]) = fifo->data[q / 4];
}
if (release) {
FDCAN_RXFIA(canport, fifo_id) = get_index << FDCAN_RXFIFO_AI_SHIFT;
}
return FDCAN_E_OK;
}
/** Release receive oldest FIFO entry.
*
* This function will mask oldest entry in FIFO as released making
* space for another received frame. This function can be used if
* fdcan_receive was called using release = false. If used in other
* case, then messages can get lost.
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @param [in] fifo_id ID of FIFO where release should be performed (0 or 1)
*/
void fdcan_release_fifo(uint32_t canport, uint8_t fifo_id)
{
unsigned pending_frames, get_index;
get_index = (FDCAN_RXFIS(canport, fifo_id) >> FDCAN_RXFIFO_GI_SHIFT)
& FDCAN_RXFIFO_GI_SHIFT;
pending_frames = (FDCAN_RXFIS(canport, fifo_id) >> FDCAN_RXFIFO_FL_SHIFT)
& FDCAN_RXFIFO_FL_SHIFT;
if (pending_frames) {
FDCAN_RXFIA(canport, fifo_id) |= get_index << FDCAN_RXFIFO_AI_SHIFT;
}
}
/** Enable IRQ from FDCAN block.
*
* This routine configures FDCAN to enable certain IRQ.
* Each FDCAN block supports two IRQs.
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @param [in] irq number of IRQ to be enabled (currently 0 or 1)
*/
void fdcan_enable_irq(uint32_t canport, uint32_t irq)
{
FDCAN_ILE(canport) |= irq & (FDCAN_ILE_INT0 | FDCAN_ILE_INT1);
}
/** Disable IRQ from FDCAN block.
*
* This routine configures FDCAN to disable certain IRQ.
* Each FDCAN block supports two IRQs.
*
* @param [in] canport FDCAN block base address. See @ref fdcan_block.
* @param [in] irq number of IRQ to be enabled (currently 0 or 1)
*/
void fdcan_disable_irq(uint32_t canport, uint32_t irq)
{
FDCAN_ILE(canport) &= ~(irq & (FDCAN_ILE_INT0 | FDCAN_ILE_INT1));
}
/** Check if there is free transmit buffer.
*
* @param [in] canport FDCAN port. See @ref fdcan_block.
* @returns true if there is at least one free transmit buffer for new message
* to be sent, false otherwise.
*/
bool fdcan_available_tx(uint32_t canport)
{
return (fdcan_get_free_txbuf(canport) != FDCAN_E_BUSY);
}
/** Tell if there is message waiting in receive FIFO.
*
* @param [in] canport FDCAN port. See @ref fdcan_block.
* @param [in] fifo Rx FIFO number, 0 or 1
* @returns true if there is at least one message waiting in given receive FIFO,
* false otherwise.
*/
bool fdcan_available_rx(uint32_t canport, uint8_t fifo)
{
unsigned pending_frames;
pending_frames = (FDCAN_RXFIS(canport, fifo) >> FDCAN_RXFIFO_FL_SHIFT)
& FDCAN_RXFIFO_FL_MASK;
return (pending_frames != 0);
}
/**@}*/

View File

@@ -0,0 +1,52 @@
/** @addtogroup flash_file FLASH peripheral API
* @ingroup peripheral_apis
*/
/*
* 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/flash.h>
void flash_prefetch_enable(void)
{
FLASH_ACR |= FLASH_ACR_PRFTEN;
}
void flash_prefetch_disable(void)
{
FLASH_ACR &= ~FLASH_ACR_PRFTEN;
}
void flash_set_ws(uint32_t ws)
{
uint32_t reg32;
reg32 = FLASH_ACR;
reg32 &= ~(FLASH_ACR_LATENCY_MASK << FLASH_ACR_LATENCY_SHIFT);
reg32 |= (ws << FLASH_ACR_LATENCY_SHIFT);
FLASH_ACR = reg32;
}
void flash_unlock_option_bytes(void)
{
FLASH_OPTKEYR = FLASH_OPTKEYR_KEY1;
FLASH_OPTKEYR = FLASH_OPTKEYR_KEY2;
}
/**@}*/

View File

@@ -0,0 +1,46 @@
/** @addtogroup flash_file
*
*/
/*
* 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/flash.h>
#include <libopencm3/stm32/common/flash_common_f.h>
void flash_unlock(void)
{
/* Authorize the FPEC access. */
FLASH_KEYR = FLASH_KEYR_KEY1;
FLASH_KEYR = FLASH_KEYR_KEY2;
}
void flash_lock(void)
{
FLASH_CR |= FLASH_CR_LOCK;
}
/* The bit number for EOP moves sometimes, but it's always a write 1 to clear */
void flash_clear_eop_flag(void)
{
FLASH_SR |= FLASH_SR_EOP;
}
/**@}*/

View File

@@ -0,0 +1,138 @@
/** @addtogroup flash_file
*
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2014 Ken Sarkies <ksarkies@internode.on.net>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/flash.h>
/*---------------------------------------------------------------------------*/
/** @brief Unlock the Flash Program and Erase Controller
This enables write access to the Flash memory. It is locked by default on
reset.
*/
/*---------------------------------------------------------------------------*/
/** @brief Clear the Programming Error Status Flag
*/
void flash_clear_pgerr_flag(void)
{
FLASH_SR |= FLASH_SR_PGERR;
}
/*---------------------------------------------------------------------------*/
/** @brief Clear the Write Protect Error Status Flag
*/
void flash_clear_wrprterr_flag(void)
{
FLASH_SR |= FLASH_SR_WRPRTERR;
}
/*---------------------------------------------------------------------------*/
/** @brief Wait until Last Operation has Ended
This loops indefinitely until an operation (write or erase) has completed by
testing the busy flag.
*/
void flash_wait_for_last_operation(void)
{
while ((flash_get_status_flags() & FLASH_SR_BSY) == FLASH_SR_BSY);
}
/*---------------------------------------------------------------------------*/
/** @brief Program a 32 bit Word to FLASH
This performs all operations necessary to program a 32 bit word to FLASH memory.
The program error flag should be checked separately for the event that memory
was not properly erased.
Status bit polling is used to detect end of operation.
@param[in] address Full address of flash word to be programmed.
@param[in] data word to write
*/
void flash_program_word(uint32_t address, uint32_t data)
{
flash_program_half_word(address, (uint16_t)data);
flash_program_half_word(address+2, (uint16_t)(data>>16));
}
/*---------------------------------------------------------------------------*/
/** @brief Erase All Option Bytes
This performs all operations necessary to erase the option bytes. These must
first be fully erased before attempting to program them, therefore it is
recommended to check these after an erase attempt.
*/
void flash_erase_option_bytes(void)
{
flash_wait_for_last_operation();
if ((FLASH_CR & FLASH_CR_OPTWRE) == 0) {
flash_unlock_option_bytes();
}
FLASH_CR |= FLASH_CR_OPTER; /* Enable option byte erase. */
FLASH_CR |= FLASH_CR_STRT;
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_OPTER; /* Disable option byte erase. */
}
/*---------------------------------------------------------------------------*/
/** @brief Program the Option Bytes
This performs all operations necessary to program the option bytes.
The write protect error flag should be checked separately for the event that
an option byte had not been properly erased before calling this function.
Only the lower 8 bits of the data is significant.
@param[in] address Address of option byte from @ref flash_options.
@param[in] data value to write
*/
void flash_program_option_bytes(uint32_t address, uint16_t data)
{
flash_wait_for_last_operation();
if ((FLASH_CR & FLASH_CR_OPTWRE) == 0) {
flash_unlock_option_bytes();
}
FLASH_CR |= FLASH_CR_OPTPG; /* Enable option byte programming. */
MMIO16(address) = data;
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_OPTPG; /* Disable option byte programming. */
}
/**@}*/

View File

@@ -0,0 +1,291 @@
/** @addtogroup flash_file
*
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/flash.h>
/*---------------------------------------------------------------------------*/
/** @brief Set the Program Parallelism Size
Set the programming word width. Note carefully the power supply voltage
restrictions under which the different word sizes may be used. See the
programming manual for more information.
@param[in] psize The programming word width one of: @ref flash_cr_program_width
*/
static inline void flash_set_program_size(uint32_t psize)
{
FLASH_CR &= ~(FLASH_CR_PROGRAM_MASK << FLASH_CR_PROGRAM_SHIFT);
FLASH_CR |= psize << FLASH_CR_PROGRAM_SHIFT;
}
/*---------------------------------------------------------------------------*/
/** @brief Clear the Programming Alignment Error Flag
*/
void flash_clear_pgaerr_flag(void)
{
FLASH_SR |= FLASH_SR_PGAERR;
}
/** Clear programming parallelism error flag
*/
void flash_clear_pgperr_flag(void)
{
FLASH_SR |= FLASH_SR_PGPERR;
}
/*---------------------------------------------------------------------------*/
/** @brief Clear the Write Protect Error Flag
*/
void flash_clear_wrperr_flag(void)
{
FLASH_SR |= FLASH_SR_WRPERR;
}
/*---------------------------------------------------------------------------*/
/** @brief Lock the Option Byte Access
This disables write access to the option bytes. It is locked by default on
reset.
*/
void flash_lock_option_bytes(void)
{
FLASH_OPTCR |= FLASH_OPTCR_OPTLOCK;
}
/*---------------------------------------------------------------------------*/
/** @brief Program a 64 bit Word to FLASH
This performs all operations necessary to program a 64 bit word to FLASH memory.
The program error flag should be checked separately for the event that memory
was not properly erased.
@param[in] address Starting address in Flash.
@param[in] data Double word to write
*/
void flash_program_double_word(uint32_t address, uint64_t data)
{
/* Ensure that all flash operations are complete. */
flash_wait_for_last_operation();
flash_set_program_size(FLASH_CR_PROGRAM_X64);
/* Enable writes to flash. */
FLASH_CR |= FLASH_CR_PG;
/* Program the double_word. */
MMIO64(address) = data;
/* Wait for the write to complete. */
flash_wait_for_last_operation();
/* Disable writes to flash. */
FLASH_CR &= ~FLASH_CR_PG;
}
/*---------------------------------------------------------------------------*/
/** @brief Program a 32 bit Word to FLASH
This performs all operations necessary to program a 32 bit word to FLASH memory.
The program error flag should be checked separately for the event that memory
was not properly erased.
@param[in] address Starting address in Flash.
@param[in] data word to write
*/
void flash_program_word(uint32_t address, uint32_t data)
{
/* Ensure that all flash operations are complete. */
flash_wait_for_last_operation();
flash_set_program_size(FLASH_CR_PROGRAM_X32);
/* Enable writes to flash. */
FLASH_CR |= FLASH_CR_PG;
/* Program the word. */
MMIO32(address) = data;
/* Wait for the write to complete. */
flash_wait_for_last_operation();
/* Disable writes to flash. */
FLASH_CR &= ~FLASH_CR_PG;
}
/*---------------------------------------------------------------------------*/
/** @brief Program a Half Word to FLASH
This performs all operations necessary to program a 16 bit word to FLASH memory.
The program error flag should be checked separately for the event that memory
was not properly erased.
@param[in] address Starting address in Flash.
@param[in] data half word to write
*/
void flash_program_half_word(uint32_t address, uint16_t data)
{
flash_wait_for_last_operation();
flash_set_program_size(FLASH_CR_PROGRAM_X16);
FLASH_CR |= FLASH_CR_PG;
MMIO16(address) = data;
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_PG; /* Disable the PG bit. */
}
/*---------------------------------------------------------------------------*/
/** @brief Program an 8 bit Byte to FLASH
This performs all operations necessary to program an 8 bit byte to FLASH memory.
The program error flag should be checked separately for the event that memory
was not properly erased.
@param[in] address Starting address in Flash.
@param[in] data byte to write
*/
void flash_program_byte(uint32_t address, uint8_t data)
{
flash_wait_for_last_operation();
flash_set_program_size(FLASH_CR_PROGRAM_X8);
FLASH_CR |= FLASH_CR_PG;
MMIO8(address) = data;
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_PG; /* Disable the PG bit. */
}
/*---------------------------------------------------------------------------*/
/** @brief Program a Data Block to FLASH
This programs an arbitrary length data block to FLASH memory.
The program error flag should be checked separately for the event that memory
was not properly erased.
@param[in] address Starting address in Flash.
@param[in] data Pointer to start of data block.
@param[in] len Length of data block.
*/
void flash_program(uint32_t address, const uint8_t *data, uint32_t len)
{
/* TODO: Use dword and word size program operations where possible for
* turbo speed.
*/
uint32_t i;
for (i = 0; i < len; i++) {
flash_program_byte(address+i, data[i]);
}
}
/*---------------------------------------------------------------------------*/
/** @brief Erase a Sector of FLASH
This performs all operations necessary to erase a sector in FLASH memory.
The page should be checked to ensure that it was properly erased. A sector must
first be fully erased before attempting to program it.
See the reference manual or the FLASH programming manual for details.
@param[in] sector (0 - 11 for some parts, 0-23 on others)
@param program_size: 0 (8-bit), 1 (16-bit), 2 (32-bit), 3 (64-bit)
*/
void flash_erase_sector(uint8_t sector, uint32_t program_size)
{
flash_wait_for_last_operation();
flash_set_program_size(program_size);
/* Sector numbering is not contiguous internally! */
if (sector >= 12) {
sector += 4;
}
FLASH_CR &= ~(FLASH_CR_SNB_MASK << FLASH_CR_SNB_SHIFT);
FLASH_CR |= (sector & FLASH_CR_SNB_MASK) << FLASH_CR_SNB_SHIFT;
FLASH_CR |= FLASH_CR_SER;
FLASH_CR |= FLASH_CR_STRT;
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_SER;
FLASH_CR &= ~(FLASH_CR_SNB_MASK << FLASH_CR_SNB_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief Erase All FLASH
This performs all operations necessary to erase all sectors in the FLASH
memory.
@param program_size: 0 (8-bit), 1 (16-bit), 2 (32-bit), 3 (64-bit)
*/
void flash_erase_all_sectors(uint32_t program_size)
{
flash_wait_for_last_operation();
flash_set_program_size(program_size);
FLASH_CR |= FLASH_CR_MER; /* Enable mass erase. */
FLASH_CR |= FLASH_CR_STRT; /* Trigger the erase. */
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_MER; /* Disable mass erase. */
}
/*---------------------------------------------------------------------------*/
/** @brief Program the Option Bytes
This performs all operations necessary to program the option bytes.
The option bytes do not need to be erased first.
@param[in] data value to be programmed.
*/
void flash_program_option_bytes(uint32_t data)
{
flash_wait_for_last_operation();
if (FLASH_OPTCR & FLASH_OPTCR_OPTLOCK) {
flash_unlock_option_bytes();
}
FLASH_OPTCR = data & ~0x3;
FLASH_OPTCR |= FLASH_OPTCR_OPTSTRT; /* Enable option byte prog. */
flash_wait_for_last_operation();
}
/**@}*/

View File

@@ -0,0 +1,59 @@
/** @addtogroup flash_file
*
*/
/*
* 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/flash.h>
#include <libopencm3/stm32/common/flash_common_idcache.h>
void flash_dcache_enable(void)
{
FLASH_ACR |= FLASH_ACR_DCEN;
}
void flash_dcache_disable(void)
{
FLASH_ACR &= ~FLASH_ACR_DCEN;
}
void flash_icache_enable(void)
{
FLASH_ACR |= FLASH_ACR_ICEN;
}
void flash_icache_disable(void)
{
FLASH_ACR &= ~FLASH_ACR_ICEN;
}
void flash_dcache_reset(void)
{
FLASH_ACR |= FLASH_ACR_DCRST;
}
void flash_icache_reset(void)
{
FLASH_ACR |= FLASH_ACR_ICRST;
}
/**@}*/

View File

@@ -0,0 +1,164 @@
/** @addtogroup flash_file
*
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
* Copyright (C) 2012-13 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Flash routines shared by L0/L1. L4 has a different flash controller */
/**@{*/
#include <libopencm3/stm32/flash.h>
/**
* Unlock primary access to the flash control/erase block
* You must call this before using any of the low level routines
* yourself.
* @sa flash_unlock
*/
void flash_unlock_pecr(void)
{
FLASH_PEKEYR = FLASH_PEKEYR_PEKEY1;
FLASH_PEKEYR = FLASH_PEKEYR_PEKEY2;
}
void flash_lock_pecr(void)
{
FLASH_PECR |= FLASH_PECR_PELOCK;
}
/**
* Unlock program memory itself.
* Writes the magic sequence to unlock the program memory
* you must have already unlocked access to this register!
* @sa flash_unlock_pecr
*/
void flash_unlock_progmem(void)
{
FLASH_PRGKEYR = FLASH_PRGKEYR_PRGKEY1;
FLASH_PRGKEYR = FLASH_PRGKEYR_PRGKEY2;
}
void flash_lock_progmem(void)
{
FLASH_PECR |= FLASH_PECR_PRGLOCK;
}
void flash_lock_option_bytes(void)
{
FLASH_PECR |= FLASH_PECR_OPTLOCK;
}
/** @brief Unlock all segments of flash
*
*/
void flash_unlock(void)
{
flash_unlock_pecr();
flash_unlock_progmem();
flash_unlock_option_bytes();
}
/** @brief Lock all segments of flash
*
*/
void flash_lock(void)
{
flash_lock_option_bytes();
flash_lock_progmem();
flash_lock_pecr();
}
/** @brief Unlock RUN_PD bit from FLASH_ACR register.
*/
void flash_unlock_acr(void)
{
FLASH_PDKEYR = FLASH_PDKEYR_PDKEY1;
FLASH_PDKEYR = FLASH_PDKEYR_PDKEY2;
}
void flash_erase_page(uint32_t page_address)
{
FLASH_PECR |= FLASH_PECR_ERASE | FLASH_PECR_PROG;
MMIO32(page_address) = 0;
while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY);
FLASH_PECR &= ~(FLASH_PECR_ERASE | FLASH_PECR_PROG);
}
/* Must be run from RAM (per ref manual), and because it's in ram, more
* than 64MB away from flash address space, must be a long_call. */
__attribute__ ((long_call, section (".ramtext")))
void flash_program_half_page(uint32_t *dst, void *buf)
{
uint32_t *src = buf;
/* Enable half page writes to program memory */
FLASH_PECR |= FLASH_PECR_FPRG | FLASH_PECR_PROG;
while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY);
for (int i = 0; i < FLASH_HALF_PAGE_SIZE; i++) {
*dst++ = *src++;
}
while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY);
FLASH_PECR &= ~(FLASH_PECR_FPRG | FLASH_PECR_PROG);
}
/** @brief Write a word to eeprom
*
* @param address assumed to be in the eeprom space, no checking
* @param data word to write
*/
void eeprom_program_word(uint32_t address, uint32_t data)
{
flash_unlock_pecr();
/* erase only if needed */
FLASH_PECR &= ~FLASH_PECR_FTDW;
MMIO32(address) = data;
flash_lock_pecr();
}
/** @brief Write a block of words to eeprom
*
* Writes a block of words to EEPROM at the requested address, erasing if
* necessary, and locking afterwards. Only wordwise writing is safe for
* writing any value
*
* @param[in] address must point to EEPROM space, no checking!
* @param[in] data pointer to data to write
* @param[in] length_in_words size of of data in WORDS!
*/
void eeprom_program_words(uint32_t address, uint32_t *data, int length_in_words)
{
int i;
flash_unlock_pecr();
while (FLASH_SR & FLASH_SR_BSY);
/* erase only if needed */
FLASH_PECR &= ~FLASH_PECR_FTDW;
for (i = 0; i < length_in_words; i++) {
MMIO32(address + (i * sizeof(uint32_t))) = *(data+i);
while (FLASH_SR & FLASH_SR_BSY);
}
flash_lock_pecr();
}
/**@}*/

View File

@@ -0,0 +1,111 @@
/** @addtogroup fmc_file FMC peripheral API
@ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies ksarkies@internode.on.net
This library supports the Flexible Memory Controller in the STM32F4xx and
STM32F7xx series of ARM Cortex Microcontrollers by ST Microelectronics.
*/
/*
*
* 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/>.
*/
/* Utility functions for the SDRAM component of the FMC */
#include <stdint.h>
#include <libopencm3/stm32/fsmc.h>
/**@{*/
/*
* Install various timing values into the correct place in the
* SDRAM Timing Control Register format.
*
* Note that the register is 'zero' based to save bits so 1 cycle
* is stored as '0'. This command takes actual cycles and adjusts
* by subtracting 1.
*/
uint32_t
sdram_timing(struct sdram_timing *t) {
uint32_t result;
result = 0;
result |= ((t->trcd - 1) & 0xf) << FMC_SDTR_TRCD_SHIFT;
result |= ((t->trp - 1) & 0xf) << FMC_SDTR_TRP_SHIFT;
result |= ((t->twr - 1) & 0xf) << FMC_SDTR_TWR_SHIFT;
result |= ((t->trc - 1) & 0xf) << FMC_SDTR_TRC_SHIFT;
result |= ((t->tras - 1) & 0xf) << FMC_SDTR_TRAS_SHIFT;
result |= ((t->txsr - 1) & 0xf) << FMC_SDTR_TXSR_SHIFT;
result |= ((t->tmrd - 1) & 0xf) << FMC_SDTR_TMRD_SHIFT;
return result;
}
/*
* Send a command to the SDRAM controller, wait until it is not
* busy before sending. This allows you to chain sending commands
* and the code will pause as needed between them.
*/
void
sdram_command(enum fmc_sdram_bank bank,
enum fmc_sdram_command cmd, int autorefresh, int modereg) {
uint32_t tmp_reg = 0;
switch (bank) {
case SDRAM_BANK1:
tmp_reg = FMC_SDCMR_CTB1;
break;
case SDRAM_BANK2:
tmp_reg = FMC_SDCMR_CTB2;
break;
case SDRAM_BOTH_BANKS:
tmp_reg = FMC_SDCMR_CTB1 | FMC_SDCMR_CTB2;
break;
}
tmp_reg |= autorefresh << FMC_SDCMR_NRFS_SHIFT;
tmp_reg |= modereg << FMC_SDCMR_MRD_SHIFT;
switch (cmd) {
case SDRAM_CLK_CONF:
tmp_reg |= FMC_SDCMR_MODE_CLOCK_CONFIG_ENA;
break;
case SDRAM_AUTO_REFRESH:
tmp_reg |= FMC_SDCMR_MODE_AUTO_REFRESH;
break;
case SDRAM_LOAD_MODE:
tmp_reg |= FMC_SDCMR_MODE_LOAD_MODE_REGISTER;
break;
case SDRAM_PALL:
tmp_reg |= FMC_SDCMR_MODE_PALL;
break;
case SDRAM_SELF_REFRESH:
tmp_reg |= FMC_SDCMR_MODE_SELF_REFRESH;
break;
case SDRAM_POWER_DOWN:
tmp_reg |= FMC_SDCMR_MODE_POWER_DOWN;
break;
case SDRAM_NORMAL:
default:
break;
}
/* Wait for the next chance to talk to the controller */
while (FMC_SDSR & FMC_SDSR_BUSY);
/* Send the next command */
FMC_SDCMR = tmp_reg;
}
/**@}*/

View File

@@ -0,0 +1,152 @@
/** @addtogroup gpio_file GPIO peripheral API
* @ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/gpio.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief Set a Group of Pins Atomic
Set one or more pins of the given GPIO port to 1 in an atomic operation.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be changed, use bitwise OR '|' to separate
them.
*/
void gpio_set(uint32_t gpioport, uint16_t gpios)
{
GPIO_BSRR(gpioport) = gpios;
}
/*---------------------------------------------------------------------------*/
/** @brief Clear a Group of Pins Atomic
Clear one or more pins of the given GPIO port to 0 in an atomic operation.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be changed, use bitwise OR '|' to separate
them.
*/
void gpio_clear(uint32_t gpioport, uint16_t gpios)
{
GPIO_BSRR(gpioport) = (gpios << 16);
}
/*---------------------------------------------------------------------------*/
/** @brief Read a Group of Pins.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be read, use bitwise OR '|' to separate
them.
@return Unsigned int16 value of the pin values. The bit position of the pin
value returned corresponds to the pin number.
*/
uint16_t gpio_get(uint32_t gpioport, uint16_t gpios)
{
return gpio_port_read(gpioport) & gpios;
}
/*---------------------------------------------------------------------------*/
/** @brief Toggle a Group of Pins
Toggle one or more pins of the given GPIO port. The toggling is not atomic, but
the non-toggled pins are not affected.
@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 bitwise OR '|' to separate
them.
*/
void gpio_toggle(uint32_t gpioport, uint16_t gpios)
{
uint32_t port = GPIO_ODR(gpioport);
GPIO_BSRR(gpioport) = ((port & gpios) << 16) | (~port & gpios);
}
/*---------------------------------------------------------------------------*/
/** @brief Read from a Port
Read the current value of the given GPIO port. Only the lower 16 bits contain
valid pin data.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@return Unsigned int16. The value held in the specified GPIO port.
*/
uint16_t gpio_port_read(uint32_t gpioport)
{
return (uint16_t)GPIO_IDR(gpioport);
}
/*---------------------------------------------------------------------------*/
/** @brief Write to a Port
Write a value to the given GPIO port.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] data Unsigned int16. The value to be written to the GPIO port.
*/
void gpio_port_write(uint32_t gpioport, uint16_t data)
{
GPIO_ODR(gpioport) = data;
}
/*---------------------------------------------------------------------------*/
/** @brief Lock the Configuration of a Group of Pins
The configuration of one or more pins of the given GPIO port is locked. There
is no mechanism to unlock these via software. Unlocking occurs at the next
reset.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be locked, use bitwise OR '|' to separate
them.
*/
void gpio_port_config_lock(uint32_t gpioport, uint16_t gpios)
{
uint32_t reg32;
/* Special "Lock Key Writing Sequence", see datasheet. */
GPIO_LCKR(gpioport) = GPIO_LCKK | gpios; /* Set LCKK. */
GPIO_LCKR(gpioport) = ~GPIO_LCKK & gpios; /* Clear LCKK. */
GPIO_LCKR(gpioport) = GPIO_LCKK | gpios; /* Set LCKK. */
reg32 = GPIO_LCKR(gpioport); /* Read LCKK. */
reg32 = GPIO_LCKR(gpioport); /* Read LCKK again. */
/* Tell the compiler the variable is actually used. It will get
* optimized out anyways.
*/
reg32 = reg32;
/* If (reg32 & GPIO_LCKK) is true, the lock is now active. */
}
/**@}*/

View File

@@ -0,0 +1,206 @@
/** @addtogroup gpio_file
@author @htmlonly &copy; @endhtmlonly 2009
Uwe Hermann <uwe@hermann-uwe.de>
@author @htmlonly &copy; @endhtmlonly 2012
Ken Sarkies <ksarkies@internode.on.net>
Each I/O port has 16 individually configurable bits. Many I/O pins share GPIO
functionality with a number of alternate functions and must be configured to
the alternate function mode if these are to be accessed. A feature is available
to remap alternative functions to a limited set of alternative pins in the
event of a clash of requirements.
The data registers associated with each port for input and output are 32 bit
with the upper 16 bits unused. The output buffer must be written as a 32 bit
word, but individual bits may be set or reset separately in atomic operations
to avoid race conditions during interrupts. Bits may also be individually
locked to prevent accidental configuration changes. Once locked the
configuration cannot be changed until after the next reset.
Each port bit can be configured as analog or digital input, the latter can be
floating or pulled up or down. As outputs they can be configured as either
push-pull or open drain, digital I/O or alternate function, and with maximum
output speeds of 2MHz, 10MHz, or 50MHz.
On reset all ports are configured as digital floating input.
@section gpio_api_ex Basic GPIO Handling API.
Example 1: Push-pull digital output actions with pullup on ports C2 and C9
@code
gpio_mode_setup(GPIOC, GPIO_MODE_OUTPUT,
GPIO_PUPD_PULLUP, GPIO2 | GPIO9);
gpio_set_output_options(GPIOC, GPIO_OTYPE_PP,
GPIO_OSPEED_25MHZ, GPIO2 | GPIO9);
gpio_set(GPIOC, GPIO2 | GPIO9);
gpio_clear(GPIOC, GPIO2);
gpio_toggle(GPIOC, GPIO2 | GPIO9);
gpio_port_write(GPIOC, 0x204);
@endcode
Example 2: Digital input on port C12 with pullup
@code
gpio_mode_setup(GPIOC, GPIO_MODE_INPUT,
GPIO_PUPD_PULLUP, GPIO12);
reg16 = gpio_port_read(GPIOC);
@endcode
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2011 Fergus Noble <fergusnoble@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/gpio.h>
/*---------------------------------------------------------------------------*/
/** @brief Set GPIO Pin Mode
Sets the Pin Direction and Analog/Digital Mode, and Output Pin Pullup,
for a set of GPIO pins on a given GPIO port.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] mode Unsigned int8. Pin mode @ref gpio_mode
@param[in] pull_up_down Unsigned int8. Pin pullup/pulldown configuration @ref
gpio_pup
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be set, use bitwise OR '|' to separate
them.
*/
void gpio_mode_setup(uint32_t gpioport, uint8_t mode, uint8_t pull_up_down,
uint16_t gpios)
{
uint16_t i;
uint32_t moder, pupd;
/*
* We want to set the config only for the pins mentioned in gpios,
* but keeping the others, so read out the actual config first.
*/
moder = GPIO_MODER(gpioport);
pupd = GPIO_PUPDR(gpioport);
for (i = 0; i < 16; i++) {
if (!((1 << i) & gpios)) {
continue;
}
moder &= ~GPIO_MODE_MASK(i);
moder |= GPIO_MODE(i, mode);
pupd &= ~GPIO_PUPD_MASK(i);
pupd |= GPIO_PUPD(i, pull_up_down);
}
/* Set mode and pull up/down control registers. */
GPIO_MODER(gpioport) = moder;
GPIO_PUPDR(gpioport) = pupd;
}
/*---------------------------------------------------------------------------*/
/** @brief Set GPIO Output Options
When the pin is set to output mode, this sets the configuration (analog/digital
and open drain/push pull) and speed, for a set of GPIO pins on a given GPIO
port.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] otype Unsigned int8. Pin output type @ref gpio_output_type
@param[in] speed Unsigned int8. Pin speed @ref gpio_speed
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be set, use bitwise OR '|' to separate
them.
*/
void gpio_set_output_options(uint32_t gpioport, uint8_t otype, uint8_t speed,
uint16_t gpios)
{
uint16_t i;
uint32_t ospeedr;
if (otype == 0x1) {
GPIO_OTYPER(gpioport) |= gpios;
} else {
GPIO_OTYPER(gpioport) &= ~gpios;
}
ospeedr = GPIO_OSPEEDR(gpioport);
for (i = 0; i < 16; i++) {
if (!((1 << i) & gpios)) {
continue;
}
ospeedr &= ~GPIO_OSPEED_MASK(i);
ospeedr |= GPIO_OSPEED(i, speed);
}
GPIO_OSPEEDR(gpioport) = ospeedr;
}
/*---------------------------------------------------------------------------*/
/** @brief Set GPIO Alternate Function Selection
Set the alternate function mapping number for each pin. Most pins have
alternate functions associated with them. When set to AF mode, a pin may be
used for one of its allocated alternate functions selected by the number given
here. To determine the number to be used for the desired function refer to the
individual datasheet for the particular device. A table is given under the Pin
Selection chapter.
Note that a number of pins may be set but only with a single AF number. In
practice this would rarely be useful as each pin is likely to require a
different number.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] alt_func_num Unsigned int8. Pin alternate function number @ref
gpio_af_num
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be set, use bitwise OR '|' to separate
them.
*/
void gpio_set_af(uint32_t gpioport, uint8_t alt_func_num, uint16_t gpios)
{
uint16_t i;
uint32_t afrl, afrh;
afrl = GPIO_AFRL(gpioport);
afrh = GPIO_AFRH(gpioport);
for (i = 0; i < 8; i++) {
if (!((1 << i) & gpios)) {
continue;
}
afrl &= ~GPIO_AFR_MASK(i);
afrl |= GPIO_AFR(i, alt_func_num);
}
for (i = 8; i < 16; i++) {
if (!((1 << i) & gpios)) {
continue;
}
afrh &= ~GPIO_AFR_MASK(i - 8);
afrh |= GPIO_AFR(i - 8, alt_func_num);
}
GPIO_AFRL(gpioport) = afrl;
GPIO_AFRH(gpioport) = afrh;
}
/**@}*/

View File

@@ -0,0 +1,164 @@
/** @addtogroup hash_file HASH Peripheral API
*
* @ingroup peripheral_apis
*
* @author @htmlonly &copy; @endhtmlonly 2013
* Mikhail Avkhimenia <mikhail@avkhimenia.net>
*
* This library supports the HASH processor in the STM32F2 and STM32F4
* series of ARM Cortex Microcontrollers by ST Microelectronics.
*
* LGPL License Terms @ref lgpl_license
* */
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2013 Mikhail Avkhimenia <mikhail@avkhimenia.net>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/hash.h>
/*---------------------------------------------------------------------------*/
/** @brief HASH Set Mode
Sets up the specified mode - either HASH or HMAC.
@param[in] mode unsigned int8. Hash processor mode: @ref hash_mode
*/
void hash_set_mode(uint8_t mode)
{
HASH_CR &= ~HASH_CR_MODE;
HASH_CR |= mode;
}
/*---------------------------------------------------------------------------*/
/** @brief HASH Set Algorithm
Sets up the specified algorithm - either MD5 or SHA1.
@param[in] algorithm unsigned int8. Hash algorithm: @ref hash_algorithm
*/
void hash_set_algorithm(uint8_t algorithm)
{
HASH_CR &= ~HASH_CR_ALGO;
HASH_CR |= algorithm;
}
/*---------------------------------------------------------------------------*/
/** @brief HASH Set Data Type
Sets up the specified data type: 32Bit, 16Bit, 8Bit, Bitstring.
@param[in] datatype unsigned int8. Hash data type: @ref hash_data_type
*/
void hash_set_data_type(uint8_t datatype)
{
HASH_CR &= ~HASH_CR_DATATYPE;
HASH_CR |= datatype;
}
/*---------------------------------------------------------------------------*/
/** @brief HASH Set Key Length
Sets up the specified key length: Long, Short.
@param[in] keylength unsigned int8. Hash data type: @ref hash_key_length
*/
void hash_set_key_length(uint8_t keylength)
{
HASH_CR &= ~HASH_CR_LKEY;
HASH_CR |= keylength;
}
/*---------------------------------------------------------------------------*/
/** @brief HASH Set Last Word Valid Bits
Specifies the number of valid bits in the last word.
@param[in] validbits unsigned int8. Number of valid bits.
*/
void hash_set_last_word_valid_bits(uint8_t validbits)
{
HASH_STR &= ~(HASH_STR_NBW);
HASH_STR |= validbits;
}
/*---------------------------------------------------------------------------*/
/** @brief HASH Init
Initializes the HASH processor.
*/
void hash_init()
{
HASH_CR |= HASH_CR_INIT;
}
/*---------------------------------------------------------------------------*/
/** @brief HASH Add data
Puts data into the HASH processor's queue.
@param[in] data unsigned int32. Hash input data.
*/
void hash_add_data(uint32_t data)
{
HASH_DIN = data;
}
/*---------------------------------------------------------------------------*/
/** @brief HASH Digest
Starts the processing of the last data block.
*/
void hash_digest()
{
HASH_STR |= HASH_STR_DCAL;
}
/*---------------------------------------------------------------------------*/
/** @brief HASH Get Hash Result
Makes a copy of the resulting hash.
@param[out] data unsigned int32. Hash 4\5 words long depending on the algorithm.
*/
void hash_get_result(uint32_t *data)
{
data[0] = HASH_HR[0];
data[1] = HASH_HR[1];
data[2] = HASH_HR[2];
data[3] = HASH_HR[3];
if ((HASH_CR & HASH_CR_ALGO) == HASH_ALGO_SHA1) {
data[4] = HASH_HR[4];
}
}
/**@}*/

View File

@@ -0,0 +1,540 @@
/** @addtogroup i2c_file I2C peripheral API
* @ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2010
Thomas Otto <tommi@viadmin.org>
@author @htmlonly &copy; @endhtmlonly 2012
Ken Sarkies <ksarkies@internode.on.net>
Devices can have up to three I2C peripherals. The peripherals support SMBus and
PMBus variants.
A peripheral begins after reset in Slave mode. To become a Master a start
condition must be generated. The peripheral will remain in Master mode unless
a multimaster contention is lost or a stop condition is generated.
@todo all sorts of lovely stuff like DMA, Interrupts, SMBus variant, Status
register access, Error conditions
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/i2c.h>
#include <libopencm3/stm32/rcc.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief I2C Peripheral Enable.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_peripheral_enable(uint32_t i2c)
{
I2C_CR1(i2c) |= I2C_CR1_PE;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Peripheral Disable.
This must not be reset while in Master mode until a communication has finished.
In Slave mode, the peripheral is disabled only after communication has ended.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_peripheral_disable(uint32_t i2c)
{
I2C_CR1(i2c) &= ~I2C_CR1_PE;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Send Start Condition.
If in Master mode this will cause a restart condition to occur at the end of the
current transmission. If in Slave mode, this will initiate a start condition
when the current bus activity is completed.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_send_start(uint32_t i2c)
{
I2C_CR1(i2c) |= I2C_CR1_START;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Send Stop Condition.
After the current byte transfer this will initiate a stop condition if in Master
mode, or simply release the bus if in Slave mode.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_send_stop(uint32_t i2c)
{
I2C_CR1(i2c) |= I2C_CR1_STOP;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Clear Stop Flag.
Clear the "Send Stop" flag in the I2C config register
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_clear_stop(uint32_t i2c)
{
I2C_CR1(i2c) &= ~I2C_CR1_STOP;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set the 7 bit Slave Address for the Peripheral.
This sets an address for Slave mode operation, in 7 bit form.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] slave Unsigned int8. Slave address 0...127.
*/
void i2c_set_own_7bit_slave_address(uint32_t i2c, uint8_t slave)
{
uint16_t val = (uint16_t)(slave << 1);
/* Datasheet: always keep 1 by software. */
val |= (1 << 14);
I2C_OAR1(i2c) = val;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set the 10 bit Slave Address for the Peripheral.
This sets an address for Slave mode operation, in 10 bit form.
@todo add "I2C_OAR1(i2c) |= (1 << 14);" as above
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] slave Unsigned int16. Slave address 0...1023.
*/
void i2c_set_own_10bit_slave_address(uint32_t i2c, uint16_t slave)
{
I2C_OAR1(i2c) = (uint16_t)(I2C_OAR1_ADDMODE | slave);
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set the secondary 7 bit Slave Address for the Peripheral.
This sets a secondary address for Slave mode operation, in 7 bit form.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] slave Unsigned int8. Slave address 0...127.
*/
void i2c_set_own_7bit_slave_address_two(uint32_t i2c, uint8_t slave)
{
uint16_t val = (uint16_t)(slave << 1);
I2C_OAR2(i2c) = val;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Enable dual addressing mode for the Peripheral.
Both OAR1 and OAR2 are recognised in 7-bit addressing mode.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_enable_dual_addressing_mode(uint32_t i2c)
{
I2C_OAR2(i2c) |= I2C_OAR2_ENDUAL;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Disable dual addressing mode for the Peripheral.
Only OAR1 is recognised in 7-bit addressing mode.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_disable_dual_addressing_mode(uint32_t i2c)
{
I2C_OAR2(i2c) &= ~(I2C_OAR2_ENDUAL);
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set Peripheral Clock Frequency.
Set the peripheral clock frequency: 2MHz to 36MHz (the APB frequency). Note
that this is <b> not </b> the I2C bus clock. This is set in conjunction with
the Clock Control register to generate the Master bus clock, see @ref
i2c_set_ccr
@param[in] i2c I2C register base address @ref i2c_reg_base
@param[in] freq Clock Frequency Setting in MHz, valid range depends on part,+
normally 2Mhz->Max APB speed.
*/
void i2c_set_clock_frequency(uint32_t i2c, uint8_t freq)
{
uint16_t reg16;
reg16 = I2C_CR2(i2c) & 0xffc0; /* Clear bits [5:0]. */
reg16 |= freq;
I2C_CR2(i2c) = reg16;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Send Data.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] data Unsigned int8. Byte to send.
*/
void i2c_send_data(uint32_t i2c, uint8_t data)
{
I2C_DR(i2c) = data;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set Fast Mode.
Set the clock frequency to the high clock rate mode (up to 400kHz). The actual
clock frequency must be set with @ref i2c_set_clock_frequency
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_set_fast_mode(uint32_t i2c)
{
I2C_CCR(i2c) |= I2C_CCR_FS;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set Standard Mode.
Set the clock frequency to the standard clock rate mode (up to 100kHz). The
actual clock frequency must be set with @ref i2c_set_clock_frequency
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_set_standard_mode(uint32_t i2c)
{
I2C_CCR(i2c) &= ~I2C_CCR_FS;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set Bus Clock Frequency.
Set the bus clock frequency. This is a 12 bit number (0...4095) calculated
from the formulae given in the STM32F1 reference manual in the description
of the CCR field. It is a divisor of the peripheral clock frequency
@ref i2c_set_clock_frequency modified by the fast mode setting
@ref i2c_set_fast_mode
@todo provide additional API assitance to set the clock, eg macros
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] freq Unsigned int16. Bus Clock Frequency Setting 0...4095.
*/
void i2c_set_ccr(uint32_t i2c, uint16_t freq)
{
uint16_t reg16;
reg16 = I2C_CCR(i2c) & 0xf000; /* Clear bits [11:0]. */
reg16 |= freq;
I2C_CCR(i2c) = reg16;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set the Rise Time.
Set the maximum rise time on the bus according to the I2C specification, as 1
more than the specified rise time in peripheral clock cycles. This is a 6 bit
number.
@todo provide additional APIP assistance.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] trise Unsigned int16. Rise Time Setting 0...63.
*/
void i2c_set_trise(uint32_t i2c, uint16_t trise)
{
I2C_TRISE(i2c) = trise;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Send the 7-bit Slave Address.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] slave Unsigned int16. Slave address 0...1023.
@param[in] readwrite Unsigned int8. Single bit to instruct slave to receive or
send @ref i2c_rw.
*/
void i2c_send_7bit_address(uint32_t i2c, uint8_t slave, uint8_t readwrite)
{
I2C_DR(i2c) = (uint8_t)((slave << 1) | readwrite);
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Get Data.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
uint8_t i2c_get_data(uint32_t i2c)
{
return I2C_DR(i2c) & 0xff;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Enable Interrupt
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] interrupt Unsigned int32. Interrupt to enable.
*/
void i2c_enable_interrupt(uint32_t i2c, uint32_t interrupt)
{
I2C_CR2(i2c) |= interrupt;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Disable Interrupt
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] interrupt Unsigned int32. Interrupt to disable.
*/
void i2c_disable_interrupt(uint32_t i2c, uint32_t interrupt)
{
I2C_CR2(i2c) &= ~interrupt;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Enable ACK
Enables acking of own 7/10 bit address
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_enable_ack(uint32_t i2c)
{
I2C_CR1(i2c) |= I2C_CR1_ACK;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Disable ACK
Disables acking of own 7/10 bit address
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_disable_ack(uint32_t i2c)
{
I2C_CR1(i2c) &= ~I2C_CR1_ACK;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C NACK Next Byte
Causes the I2C controller to NACK the reception of the next byte
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_nack_next(uint32_t i2c)
{
I2C_CR1(i2c) |= I2C_CR1_POS;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C NACK Next Byte
Causes the I2C controller to NACK the reception of the current byte
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_nack_current(uint32_t i2c)
{
I2C_CR1(i2c) &= ~I2C_CR1_POS;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set clock duty cycle
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] dutycycle Unsigned int32. I2C duty cycle @ref i2c_duty_cycle.
*/
void i2c_set_dutycycle(uint32_t i2c, uint32_t dutycycle)
{
if (dutycycle == I2C_CCR_DUTY_DIV2) {
I2C_CCR(i2c) &= ~I2C_CCR_DUTY;
} else {
I2C_CCR(i2c) |= I2C_CCR_DUTY;
}
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Enable DMA
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_enable_dma(uint32_t i2c)
{
I2C_CR2(i2c) |= I2C_CR2_DMAEN;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Disable DMA
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_disable_dma(uint32_t i2c)
{
I2C_CR2(i2c) &= ~I2C_CR2_DMAEN;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set DMA last transfer
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_set_dma_last_transfer(uint32_t i2c)
{
I2C_CR2(i2c) |= I2C_CR2_LAST;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Clear DMA last transfer
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_clear_dma_last_transfer(uint32_t i2c)
{
I2C_CR2(i2c) &= ~I2C_CR2_LAST;
}
static void i2c_write7_v1(uint32_t i2c, int addr, const uint8_t *data, size_t n)
{
while ((I2C_SR2(i2c) & I2C_SR2_BUSY)) {
}
i2c_send_start(i2c);
/* Wait for the end of the start condition, master mode selected, and BUSY bit set */
while ( !( (I2C_SR1(i2c) & I2C_SR1_SB)
&& (I2C_SR2(i2c) & I2C_SR2_MSL)
&& (I2C_SR2(i2c) & I2C_SR2_BUSY) ));
i2c_send_7bit_address(i2c, addr, I2C_WRITE);
/* Waiting for address is transferred. */
while (!(I2C_SR1(i2c) & I2C_SR1_ADDR));
/* Clearing ADDR condition sequence. */
(void)I2C_SR2(i2c);
for (size_t i = 0; i < n; i++) {
i2c_send_data(i2c, data[i]);
while (!(I2C_SR1(i2c) & (I2C_SR1_BTF)));
}
}
static void i2c_read7_v1(uint32_t i2c, int addr, uint8_t *res, size_t n)
{
i2c_send_start(i2c);
i2c_enable_ack(i2c);
/* Wait for the end of the start condition, master mode selected, and BUSY bit set */
while ( !( (I2C_SR1(i2c) & I2C_SR1_SB)
&& (I2C_SR2(i2c) & I2C_SR2_MSL)
&& (I2C_SR2(i2c) & I2C_SR2_BUSY) ));
i2c_send_7bit_address(i2c, addr, I2C_READ);
/* Waiting for address is transferred. */
while (!(I2C_SR1(i2c) & I2C_SR1_ADDR));
/* Clearing ADDR condition sequence. */
(void)I2C_SR2(i2c);
for (size_t i = 0; i < n; ++i) {
if (i == n - 1) {
i2c_disable_ack(i2c);
}
while (!(I2C_SR1(i2c) & I2C_SR1_RxNE));
res[i] = i2c_get_data(i2c);
}
i2c_send_stop(i2c);
return;
}
/**
* Run a write/read transaction to a given 7bit i2c address
* If both write & read are provided, the read will use repeated start.
* Both write and read are optional
* There are likely still issues with repeated start/stop condtions!
* @param i2c peripheral of choice, eg I2C1
* @param addr 7 bit i2c device address
* @param w buffer of data to write
* @param wn length of w
* @param r destination buffer to read into
* @param rn number of bytes to read (r should be at least this long)
*/
void i2c_transfer7(uint32_t i2c, uint8_t addr, const uint8_t *w, size_t wn, uint8_t *r, size_t rn) {
if (wn) {
i2c_write7_v1(i2c, addr, w, wn);
}
if (rn) {
i2c_read7_v1(i2c, addr, r, rn);
} else {
i2c_send_stop(i2c);
}
}
/**
* Set the i2c communication speed.
* @param i2c peripheral, eg I2C1
* @param speed one of the listed speed modes @ref i2c_speeds
* @param clock_megahz i2c peripheral clock speed in MHz. Usually, rcc_apb1_frequency / 1e6
*/
void i2c_set_speed(uint32_t i2c, enum i2c_speeds speed, uint32_t clock_megahz)
{
i2c_set_clock_frequency(i2c, clock_megahz);
switch(speed) {
case i2c_speed_fm_400k:
i2c_set_fast_mode(i2c);
i2c_set_ccr(i2c, clock_megahz * 5 / 6);
i2c_set_trise(i2c, clock_megahz + 1);
break;
default:
/* fall back to standard mode */
case i2c_speed_sm_100k:
i2c_set_standard_mode(i2c);
/* x Mhz / (100kHz * 2) */
i2c_set_ccr(i2c, clock_megahz * 5);
/* Sm mode, (100kHz) freqMhz + 1 */
i2c_set_trise(i2c, clock_megahz + 1);
break;
}
}
/**@}*/

View File

@@ -0,0 +1,450 @@
/** @addtogroup i2c_file I2C peripheral API
* @ingroup peripheral_apis
*/
/*
* This file is part of the libopencm3 project.
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/i2c.h>
#include <libopencm3/stm32/rcc.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief I2C Peripheral Enable.
*
* @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_peripheral_enable(uint32_t i2c)
{
I2C_CR1(i2c) |= I2C_CR1_PE;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Peripheral Disable.
*
* This must not be reset while in Master mode until a communication has
* finished. In Slave mode, the peripheral is disabled only after communication
* has ended.
*
* @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_peripheral_disable(uint32_t i2c)
{
I2C_CR1(i2c) &= ~I2C_CR1_PE;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Send Start Condition.
*
* If in Master mode this will cause a restart condition to occur at the end of
* the current transmission. If in Slave mode, this will initiate a start
* condition when the current bus activity is completed.
*
* @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_send_start(uint32_t i2c)
{
I2C_CR2(i2c) |= I2C_CR2_START;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Send Stop Condition.
*
* After the current byte transfer this will initiate a stop condition if in
* Master mode, or simply release the bus if in Slave mode.
*
* @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_send_stop(uint32_t i2c)
{
I2C_CR2(i2c) |= I2C_CR2_STOP;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Clear Stop Flag.
*
* Clear the "Send Stop" flag in the I2C config register
*
* @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_clear_stop(uint32_t i2c)
{
I2C_ICR(i2c) |= I2C_ICR_STOPCF;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set the 7 bit Slave Address for the Peripheral.
*
* This sets an address for Slave mode operation, in 7 bit form.
*
* @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
* @param[in] slave Unsigned int8. Slave address 0...127.
*/
void i2c_set_own_7bit_slave_address(uint32_t i2c, uint8_t slave)
{
I2C_OAR1(i2c) = (uint16_t)(slave << 1);
I2C_OAR1(i2c) &= ~I2C_OAR1_OA1MODE;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set the 10 bit Slave Address for the Peripheral.
*
* This sets an address for Slave mode operation, in 10 bit form.
*
* @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
* @param[in] slave Unsigned int16. Slave address 0...1023.
*/
void i2c_set_own_10bit_slave_address(uint32_t i2c, uint16_t slave)
{
I2C_OAR1(i2c) = (uint16_t)(I2C_OAR1_OA1MODE | slave);
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Send Data.
*
* @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
* @param[in] data Unsigned int8. Byte to send.
*/
void i2c_send_data(uint32_t i2c, uint8_t data)
{
I2C_TXDR(i2c) = data;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Get Data.
*
* @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
uint8_t i2c_get_data(uint32_t i2c)
{
return I2C_RXDR(i2c) & 0xff;
}
void i2c_enable_analog_filter(uint32_t i2c)
{
I2C_CR1(i2c) &= ~I2C_CR1_ANFOFF;
}
void i2c_disable_analog_filter(uint32_t i2c)
{
I2C_CR1(i2c) |= I2C_CR1_ANFOFF;
}
/**
* Set the I2C digital filter.
* These bits are used to configure the digital noise filter on SDA and
* SCL input. The digital filter will filter spikes with a length of up
* to dnf_setting * I2CCLK clocks
* @param i2c peripheral of interest
* @param dnf_setting 0 to disable, else 1..15 i2c clocks
*/
void i2c_set_digital_filter(uint32_t i2c, uint8_t dnf_setting)
{
I2C_CR1(i2c) = (I2C_CR1(i2c) & ~(I2C_CR1_DNF_MASK << I2C_CR1_DNF_SHIFT)) |
(dnf_setting << I2C_CR1_DNF_SHIFT);
}
/* t_presc= (presc+1)*t_i2cclk */
void i2c_set_prescaler(uint32_t i2c, uint8_t presc)
{
I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_PRESC_MASK) |
(presc << I2C_TIMINGR_PRESC_SHIFT);
}
void i2c_set_data_setup_time(uint32_t i2c, uint8_t s_time)
{
I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_SCLDEL_MASK) |
(s_time << I2C_TIMINGR_SCLDEL_SHIFT);
}
void i2c_set_data_hold_time(uint32_t i2c, uint8_t h_time)
{
I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_SDADEL_MASK) |
(h_time << I2C_TIMINGR_SDADEL_SHIFT);
}
void i2c_set_scl_high_period(uint32_t i2c, uint8_t period)
{
I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_SCLH_MASK) |
(period << I2C_TIMINGR_SCLH_SHIFT);
}
void i2c_set_scl_low_period(uint32_t i2c, uint8_t period)
{
I2C_TIMINGR(i2c) = (I2C_TIMINGR(i2c) & ~I2C_TIMINGR_SCLL_MASK) |
(period << I2C_TIMINGR_SCLL_SHIFT);
}
void i2c_enable_stretching(uint32_t i2c)
{
I2C_CR1(i2c) &= ~I2C_CR1_NOSTRETCH;
}
void i2c_disable_stretching(uint32_t i2c)
{
I2C_CR1(i2c) |= I2C_CR1_NOSTRETCH;
}
void i2c_set_7bit_addr_mode(uint32_t i2c)
{
I2C_CR2(i2c) &= ~I2C_CR2_ADD10;
}
void i2c_set_10bit_addr_mode(uint32_t i2c)
{
I2C_CR2(i2c) |= I2C_CR2_ADD10;
}
void i2c_set_7bit_address(uint32_t i2c, uint8_t addr)
{
I2C_CR2(i2c) = (I2C_CR2(i2c) & ~I2C_CR2_SADD_7BIT_MASK) |
((addr & 0x7F) << I2C_CR2_SADD_7BIT_SHIFT);
}
void i2c_set_10bit_address(uint32_t i2c, uint16_t addr)
{
I2C_CR2(i2c) = (I2C_CR2(i2c) & ~I2C_CR2_SADD_10BIT_MASK) |
((addr & 0x3FF) << I2C_CR2_SADD_10BIT_SHIFT);
}
void i2c_set_write_transfer_dir(uint32_t i2c)
{
I2C_CR2(i2c) &= ~I2C_CR2_RD_WRN;
}
void i2c_set_read_transfer_dir(uint32_t i2c)
{
I2C_CR2(i2c) |= I2C_CR2_RD_WRN;
}
void i2c_set_bytes_to_transfer(uint32_t i2c, uint32_t n_bytes)
{
I2C_CR2(i2c) = (I2C_CR2(i2c) & ~I2C_CR2_NBYTES_MASK) |
(n_bytes << I2C_CR2_NBYTES_SHIFT);
}
bool i2c_is_start(uint32_t i2c)
{
return (I2C_CR2(i2c) & I2C_CR2_START);
}
void i2c_enable_autoend(uint32_t i2c)
{
I2C_CR2(i2c) |= I2C_CR2_AUTOEND;
}
void i2c_disable_autoend(uint32_t i2c)
{
I2C_CR2(i2c) &= ~I2C_CR2_AUTOEND;
}
bool i2c_nack(uint32_t i2c)
{
return (I2C_ISR(i2c) & I2C_ISR_NACKF);
}
bool i2c_busy(uint32_t i2c)
{
return (I2C_ISR(i2c) & I2C_ISR_BUSY);
}
bool i2c_transmit_int_status(uint32_t i2c)
{
return (I2C_ISR(i2c) & I2C_ISR_TXIS);
}
bool i2c_transfer_complete(uint32_t i2c)
{
return (I2C_ISR(i2c) & I2C_ISR_TC);
}
bool i2c_received_data(uint32_t i2c)
{
return (I2C_ISR(i2c) & I2C_ISR_RXNE);
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Enable Interrupt
*
* @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
* @param[in] interrupt Unsigned int32. Interrupt to enable.
*/
void i2c_enable_interrupt(uint32_t i2c, uint32_t interrupt)
{
I2C_CR1(i2c) |= interrupt;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Disable Interrupt
*
* @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
* @param[in] interrupt Unsigned int32. Interrupt to disable.
*/
void i2c_disable_interrupt(uint32_t i2c, uint32_t interrupt)
{
I2C_CR1(i2c) &= ~interrupt;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Enable reception DMA
*
* @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_enable_rxdma(uint32_t i2c)
{
I2C_CR1(i2c) |= I2C_CR1_RXDMAEN;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Disable reception DMA
*
* @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_disable_rxdma(uint32_t i2c)
{
I2C_CR1(i2c) &= ~I2C_CR1_RXDMAEN;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Enable transmission DMA
*
* @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_enable_txdma(uint32_t i2c)
{
I2C_CR1(i2c) |= I2C_CR1_TXDMAEN;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Disable transmission DMA
*
* @param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_disable_txdma(uint32_t i2c)
{
I2C_CR1(i2c) &= ~I2C_CR1_TXDMAEN;
}
/**
* Run a write/read transaction to a given 7bit i2c address
* If both write & read are provided, the read will use repeated start.
* Both write and read are optional
* @param i2c peripheral of choice, eg I2C1
* @param addr 7 bit i2c device address
* @param w buffer of data to write
* @param wn length of w
* @param r destination buffer to read into
* @param rn number of bytes to read (r should be at least this long)
*/
void i2c_transfer7(uint32_t i2c, uint8_t addr, const uint8_t *w, size_t wn, uint8_t *r, size_t rn)
{
/* waiting for busy is unnecessary. read the RM */
if (wn) {
i2c_set_7bit_address(i2c, addr);
i2c_set_write_transfer_dir(i2c);
i2c_set_bytes_to_transfer(i2c, wn);
if (rn) {
i2c_disable_autoend(i2c);
} else {
i2c_enable_autoend(i2c);
}
i2c_send_start(i2c);
while (wn--) {
bool wait = true;
while (wait) {
if (i2c_transmit_int_status(i2c)) {
wait = false;
}
while (i2c_nack(i2c)); /* FIXME Some error */
}
i2c_send_data(i2c, *w++);
}
/* not entirely sure this is really necessary.
* RM implies it will stall until it can write out the later bits
*/
if (rn) {
while (!i2c_transfer_complete(i2c));
}
}
if (rn) {
/* Setting transfer properties */
i2c_set_7bit_address(i2c, addr);
i2c_set_read_transfer_dir(i2c);
i2c_set_bytes_to_transfer(i2c, rn);
/* start transfer */
i2c_send_start(i2c);
/* important to do it afterwards to do a proper repeated start! */
i2c_enable_autoend(i2c);
for (size_t i = 0; i < rn; i++) {
while (i2c_received_data(i2c) == 0);
r[i] = i2c_get_data(i2c);
}
}
}
/**
* Set the i2c communication speed.
* NOTE: 1MHz mode not yet implemented!
* Min clock speed: 8MHz for FM, 2Mhz for SM,
* @param i2c peripheral, eg I2C1
* @param speed one of the listed speed modes @ref i2c_speeds
* @param clock_megahz i2c peripheral clock speed in MHz. Usually, rcc_apb1_frequency / 1e6
*/
void i2c_set_speed(uint32_t i2c, enum i2c_speeds speed, uint32_t clock_megahz)
{
int prescaler;
switch(speed) {
case i2c_speed_fmp_1m:
/* FIXME - add support for this mode! */
break;
case i2c_speed_fm_400k:
/* target 8Mhz input, so tpresc = 125ns */
prescaler = clock_megahz / 8 - 1;
i2c_set_prescaler(i2c, prescaler);
i2c_set_scl_low_period(i2c, 10-1); // 1250ns
i2c_set_scl_high_period(i2c, 4-1); // 500ns
i2c_set_data_hold_time(i2c, 3); // 375ns
i2c_set_data_setup_time(i2c, 4-1); // 500ns
break;
default:
/* fall back to standard mode */
case i2c_speed_sm_100k:
/* target 4Mhz input, so tpresc = 250ns */
prescaler = (clock_megahz / 4) - 1;
i2c_set_prescaler(i2c, prescaler);
i2c_set_scl_low_period(i2c, 20-1); // 5usecs
i2c_set_scl_high_period(i2c, 16-1); // 4usecs
i2c_set_data_hold_time(i2c, 2); // 0.5usecs
i2c_set_data_setup_time(i2c, 5-1); // 1.25usecs
break;
}
}
/**@}*/

View File

@@ -0,0 +1,152 @@
/** @addtogroup iwdg_file IWDG peripheral API
@ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies ksarkies@internode.on.net
This library supports the Independent Watchdog Timer System in the STM32F1xx
series of ARM Cortex Microcontrollers by ST Microelectronics.
The watchdog timer uses the LSI (low speed internal) clock which is low power
and continues to operate during stop and standby modes. Its frequency is
nominally 32kHz (40kHz for the STM32F1xx series) but can vary from as low
as 17kHz up to 60kHz (refer to datasheet electrical characteristics).
Note that the User Configuration option byte provides a means of automatically
enabling the IWDG timer at power on (with counter value 0xFFF). If the
relevant bit is not set, the IWDG timer must be enabled by software.
@note: Tested: CPU STM32F103RET6, Board ET-ARM Stamp STM32
*/
/*
* This file is part of the libopencm3 project.
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/iwdg.h>
#define LSI_FREQUENCY 32000
#define COUNT_LENGTH 12
#define COUNT_MASK ((1 << COUNT_LENGTH)-1)
/*---------------------------------------------------------------------------*/
/** @brief IWDG Enable Watchdog Timer
The watchdog timer is started. The timeout period defaults to 512 milliseconds
unless it has been previously defined.
*/
void iwdg_start(void)
{
IWDG_KR = IWDG_KR_START;
}
/*---------------------------------------------------------------------------*/
/** @brief IWDG Set Period in Milliseconds
The countdown period is converted into count and prescale values. The maximum
period is 32.76 seconds; values above this are truncated. Periods less than 1ms
are not supported by this library.
A delay of up to 5 clock cycles of the LSI clock (about 156 microseconds)
can occasionally occur if the prescale or preload registers are currently busy
loading a previous value.
@param[in] period uint32_t Period in milliseconds (< 32760) from a watchdog
reset until a system reset is issued.
*/
void iwdg_set_period_ms(uint32_t period)
{
const int PRESCALER_MAX = 6;
uint8_t prescale = 0;
/* Set the count to represent ticks of 8kHz clock (the 32kHz LSI clock
* divided by 4 = lowest prescaler setting)
*/
uint32_t count = period << 3;
/* Prevent underflow */
if (count == 0) {
count = 1;
}
/* Shift count while increasing prescaler as many times as needed to
* fit into IWDG_RLR
*/
while ((count - 1) >> COUNT_LENGTH) {
count >>= 1;
prescale++;
}
/* IWDG_RLR actually holds count - 1 */
count--;
/* Clamp to max possible period */
if (prescale > PRESCALER_MAX) {
count = COUNT_MASK;
prescale = PRESCALER_MAX;
}
while (iwdg_prescaler_busy());
IWDG_KR = IWDG_KR_UNLOCK;
IWDG_PR = prescale;
while (iwdg_reload_busy());
IWDG_KR = IWDG_KR_UNLOCK;
IWDG_RLR = count & COUNT_MASK;
/* Refresh counter after configuration is complete */
iwdg_reset();
}
/*---------------------------------------------------------------------------*/
/** @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;
}
/**@}*/

View File

@@ -0,0 +1,294 @@
/** @addtogroup lptimer_file LPTIM peripheral API
* @ingroup peripheral_apis
*
* @author @htmlonly &copy; @endhtmlonly 2019 Guillaume Revaillot <g.revaillot@gmail.com>
*
* @date 2 July 2019
*
* LGPL License Terms @ref lgpl_license
*
* @section lptim_api_ex Basic LPTIMER handling API.
*
* Example: LPTIM1 with 2x clock prescaler, from internal clock (LSE), irq on match and reload.
*
* @code
*
* rcc_set_peripheral_clk_sel(LPTIM1, RCC_CCIPR_LPTIM1SEL_LSE);
*
* rcc_periph_clock_enable(RCC_LPTIM1);
*
* lptimer_set_internal_clock_source(LPTIM1);
* lptimer_enable_trigger(LPTIM1, LPTIM_CFGR_TRIGEN_SW);
* lptimer_set_prescaler(LPTIM1, LPTIM_CFGR_PRESC_2);
*
* lptimer_enable(LPTIM1);
*
* lptimer_set_period(LPTIM1, 0xffff);
* lptimer_set_compare(LPTIM1, 1234);
*
* lptimer_enable_irq(LPTIM1, LPTIM_IER_ARRMIE | LPTIM_IER_CMPMIE);
* nvic_enable_irq(NVIC_LPTIM1_IRQ);
*
* lptimer_start_counter(LPTIM1, LPTIM_CR_CNTSTRT);
*
* @endcode
*
* Note: LPTIM internal clock source selection is device specific, see clock tree
* and rcc section of reference manual.
*
*/
/*
* 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/lptimer.h>
/** @brief Set lptimer Counter
*
* Set the value of a lptimer counter.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
* @param[in] count Counter value.
*/
void lptimer_set_counter(uint32_t lptimer_peripheral, uint16_t count)
{
LPTIM_CNT(lptimer_peripheral) = count;
}
/** @brief Read lptimer Counter
*
* Read back the value of lptimer counter.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
* @returns Counter value.
*/
uint16_t lptimer_get_counter(uint32_t lptimer_peripheral)
{
return LPTIM_CNT(lptimer_peripheral);
}
/** @brief Clear lptimer Status Flag.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
* @param[in] flag Status Register clear flag (@ref lptim_icr)
*/
void lptimer_clear_flag(uint32_t lptimer_peripheral, uint32_t flag)
{
LPTIM_ICR(lptimer_peripheral) = flag;
}
/** @brief Read lptimer Status Flag.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
* @param[in] flag Status Register flag (@ref lptim_isr)
* @returns flag set.
*/
bool lptimer_get_flag(uint32_t lptimer_peripheral, uint32_t flag)
{
return (LPTIM_ISR(lptimer_peripheral) & flag);
}
/*---------------------------------------------------------------------------*/
/** @brief Enable lptimer interrupts.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
* @param[in] irq Logical or of all interrupt enable bits to be set (@ref lptim_ier)
*/
void lptimer_enable_irq(uint32_t lptimer_peripheral, uint32_t irq)
{
LPTIM_IER(lptimer_peripheral) |= irq;
}
/*---------------------------------------------------------------------------*/
/** @brief Disable lptimer Interrupts.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
* @param[in] irq Logical or of all interrupt enable bits to be cleared (@ref lptim_ier)
*/
void lptimer_disable_irq(uint32_t lptimer_peripheral, uint32_t irq)
{
LPTIM_IER(lptimer_peripheral) &= ~irq;
}
/** @brief Enable lptimer.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
*/
void lptimer_enable(uint32_t lptimer_peripheral)
{
LPTIM_CR(lptimer_peripheral) |= LPTIM_CR_ENABLE;
}
/** @brief Disable lptimer.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
*/
void lptimer_disable(uint32_t lptimer_peripheral)
{
LPTIM_CR(lptimer_peripheral) &= ~LPTIM_CR_ENABLE;
}
/** @brief Start lptimer in a given mode.
*
* Starts the timer in specified mode - Either Single (@ref LPTIM_CR_SNGSTRT) or
* Continuous mode (@ref LPTIM_CR_CNTSTRT). In Single mode, the timer will stop at
* next match on compare or period value.
* If LPTIM_CR_SNGSTRT is set while timer is started in countious mode, it
* will stop at next match on compare or period value.
* If Software trigger is disabled, start will be delayed until programmed
* triggers is detected.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
* @param[in] mode lptimer start mode (@ref LPTIM_CR_SNGSTRT or @ref LPTIM_CR_CNTSTRT)
*/
void lptimer_start_counter(uint32_t lptimer_peripheral, uint32_t mode)
{
LPTIM_CR(lptimer_peripheral) |= mode;
}
/** @brief Set lptimer clock prescaler.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
* @param[in] prescaler Clock prescaler (@ref lptim_cfgr_presc)
*/
void lptimer_set_prescaler(uint32_t lptimer_peripheral, uint32_t prescaler)
{
uint32_t reg32 = LPTIM_CFGR(lptimer_peripheral);
reg32 &= ~(LPTIM_CFGR_PRESC_MASK << LPTIM_CFGR_PRESC_SHIFT);
LPTIM_CFGR(lptimer_peripheral) = reg32 | prescaler;
}
/** @brief Enable lptimer External Trigger
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
* @param[in] trigen Enable Trigger
*/
void lptimer_enable_trigger(uint32_t lptimer_peripheral, uint32_t trigen)
{
uint32_t reg32 = LPTIM_CFGR(lptimer_peripheral);
reg32 &= ~(LPTIM_CFGR_TRIGEN_MASK << LPTIM_CFGR_TRIGEN_SHIFT);
LPTIM_CFGR(lptimer_peripheral) = reg32 | trigen;
}
/** @brief Select lptimer Trigger Source
*
* Select timer external trigger source.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
* @param[in] trigger_source Trigger selector (@ref lptim_cfgr_trigsel)
*/
void lptimer_select_trigger_source(uint32_t lptimer_peripheral, uint32_t trigger_source)
{
uint32_t reg32 = LPTIM_CFGR(lptimer_peripheral);
reg32 &= ~(LPTIM_CFGR_TRIGSEL_MASK << LPTIM_CFGR_TRIGSEL_SHIFT);
LPTIM_CFGR(lptimer_peripheral) = reg32 | trigger_source;
}
/** @brief Set lptimer counter Compare Value
*
* Set the timer compare value. Must only be set with timer enabled.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
* @param[in] compare_value Compare value.
*/
void lptimer_set_compare(uint32_t lptimer_peripheral, uint16_t compare_value)
{
LPTIM_CMP(lptimer_peripheral) = compare_value;
}
/** @brief Set lptimer period
*
* Set the timer period in the auto-reload register. Must only be set with timer
* enabled.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
* @param[in] period_value Autoreload value. Must be greater that CMP value.
*/
void lptimer_set_period(uint32_t lptimer_peripheral, uint16_t period_value)
{
LPTIM_ARR(lptimer_peripheral) = period_value;
}
/** @brief Enable lptimer Preload mode.
*
* Enable lptimer preload mode, delaying update of period and compare registers
* to the end of current period.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
*/
void lptimer_enable_preload(uint32_t lptimer_peripheral)
{
LPTIM_CFGR(lptimer_peripheral) |= LPTIM_CFGR_PRELOAD;
}
/** @brief Disable lptimer Preload mode.
*
* Disable lptimer preload mode, ensureing updated period and compare registers
* values are taken in account immediatly.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
*/
void lptimer_disable_preload(uint32_t lptimer_peripheral)
{
LPTIM_CFGR(lptimer_peripheral) &= ~LPTIM_CFGR_PRELOAD;
}
/** @brief Set lptimer Internal Clock source
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
*/
void lptimer_set_internal_clock_source(uint32_t lptimer_peripheral)
{
LPTIM_CFGR(lptimer_peripheral) &= ~LPTIM_CFGR_CKSEL;
}
/** @brief Set lptimer External Clock source
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
*/
void lptimer_set_external_clock_source(uint32_t lptimer_peripheral)
{
LPTIM_CFGR(lptimer_peripheral) |= LPTIM_CFGR_CKSEL;
}
/** @brief Set lptimer Waveform Output Polarity High
*
* Set lptimer waveform output to reflect compare result between LPTIN_CNT
* and LPTIM_CMP.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
*/
void lptimer_set_waveform_polarity_high(uint32_t lptimer_peripheral)
{
LPTIM_CFGR(lptimer_peripheral) |= LPTIM_CFGR_WAVPOL;
}
/** @brief Set lptimer Waveform Output Polarity Low
*
* Set lptimer waveform output to reflect the inverse of the compare result
* between LPTIN_CNT and LPTIM_CMP.
*
* @param[in] lptimer_peripheral lptimer base address (@ref lptim_reg_base)
*/
void lptimer_set_waveform_polarity_low(uint32_t lptimer_peripheral)
{
LPTIM_CFGR(lptimer_peripheral) &= ~LPTIM_CFGR_WAVPOL;
}
/**@}*/

View File

@@ -0,0 +1,92 @@
/** @defgroup ltdc_file LTDC peripheral API
*
* @ingroup peripheral_apis
*
* @version 1.0.0
*
* @author @htmlonly &copy; @endhtmlonly 2014
* Oliver Meier <h2obrain@gmail.com>
*
* @date 5 December 2014
*
* This library supports the LCD controller (LTDC) in the STM32F4xx and
* STM32F7xx series of ARM Cortex Microcontrollers by ST Microelectronics.
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2014 Oliver Meier <h2obrain@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/common/ltdc_common_f47.h>
void ltdc_set_tft_sync_timings(uint16_t sync_width, uint16_t sync_height,
uint16_t h_back_porch, uint16_t v_back_porch,
uint16_t active_width, uint16_t active_height,
uint16_t h_front_porch, uint16_t v_front_porch)
{
/*assert((active_width <= 0x400) && (active_height <= 0x300));*/
uint16_t w, h;
w = sync_width - 1;
h = sync_height - 1;
/*assert((w&0xfff == w) && (h&0x7ff == h));*/
LTDC_SSCR = (w << 16) | (h << 0);
w += h_back_porch;
h += v_back_porch;
/*assert((w&0xfff == w) && (h&0x7ff == h));*/
LTDC_BPCR = (w << 16) | (h << 0);
w += active_width;
h += active_height;
/*assert((w&0xfff == w) && (h&0x7ff == h));*/
LTDC_AWCR = (w << 16) | (h << 0);
w += h_front_porch;
h += v_front_porch;
/*assert((w&0xfff == w) && (h&0x7ff == h));*/
LTDC_TWCR = (w << 16) | (h << 0);
}
/*---------------------------------------------------------------------------*/
/** @brief LTDC Windowing Setup
@param[in] layer_number unsigned int8. @ref ltdc_layer_num
@param[in] h_back_porch unsigned int16. Horizontal Back Porch
@param[in] v_back_porch unsigned int16. Vertical Back Porch
@param[in] h_sync unsigned int16. Horizontal Sync
@param[in] v_sync unsigned int16. Vertical Sync
@param[in] width unsigned int16. Width of the screen (e.g. LCD is 320x240, width
would be 320)
@param[in] height unsigned int16. Height of the screen (e.g. LCD is 320x240,
height would be 240)
*/
void ltdc_setup_windowing(uint8_t layer_number, uint16_t h_back_porch,
uint16_t v_back_porch, uint16_t h_sync,
uint16_t v_sync, uint16_t width, uint16_t height) {
LTDC_LxWHPCR(layer_number) = (h_back_porch + width + h_sync - 1) << LTDC_LxWHPCR_WHSPPOS_SHIFT |
(h_sync + h_back_porch) << LTDC_LxWHPCR_WHSTPOS_SHIFT;
LTDC_LxWVPCR(layer_number) = (v_back_porch + height + v_sync - 1) << LTDC_LxWVPCR_WVSPPOS_SHIFT |
(v_back_porch + v_sync) << LTDC_LxWVPCR_WVSTPOS_SHIFT;
}
/**@}*/

View File

@@ -0,0 +1,112 @@
/** @addtogroup opamp_file OPAMP peripheral API
* @ingroup peripheral_apis
*/
/*
* 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/opamp.h>
void opamp_enable(uint32_t base)
{
OPAMP_CSR(base) |= OPAMP_CSR_EN;
}
void opamp_disable(uint32_t base)
{
OPAMP_CSR(base) &= ~OPAMP_CSR_EN;
}
void opamp_lock(uint32_t base)
{
OPAMP_CSR(base) |= OPAMP_CSR_LOCK;
}
void opamp_set_calsel(uint32_t base, uint32_t calsel)
{
OPAMP_CSR(base) &= ~(OPAMP_CSR_CALSEL_MASK << OPAMP_CSR_CALSEL_SHIFT);
OPAMP_CSR(base) |= calsel << OPAMP_CSR_CALSEL_SHIFT;
}
void opamp_force_vp_enable(uint32_t base)
{
OPAMP_CSR(base) |= OPAMP_CSR_FORCE_VP;
}
void opamp_force_vp_disable(uint32_t base)
{
OPAMP_CSR(base) &= ~OPAMP_CSR_FORCE_VP;
}
void opamp_cal_enable(uint32_t base)
{
OPAMP_CSR(base) |= OPAMP_CSR_CALON;
}
void opamp_cal_disable(uint32_t base)
{
OPAMP_CSR(base) &= ~OPAMP_CSR_CALON;
}
void opamp_trimoffsetn_set(uint32_t base, uint32_t trim)
{
OPAMP_CSR(base) &= ~(OPAMP_CSR_TRIMOFFSETN_MASK
<< OPAMP_CSR_TRIMOFFSETN_SHIFT);
OPAMP_CSR(base) |= trim << OPAMP_CSR_TRIMOFFSETN_SHIFT;
}
void opamp_trimoffsetp_set(uint32_t base, uint32_t trim)
{
OPAMP_CSR(base) &= ~(OPAMP_CSR_TRIMOFFSETP_MASK
<< OPAMP_CSR_TRIMOFFSETP_SHIFT);
OPAMP_CSR(base) |= trim << OPAMP_CSR_TRIMOFFSETP_SHIFT;
}
void opamp_user_trim_enable(uint32_t base)
{
OPAMP_CSR(base) |= OPAMP_CSR_USER_TRIM;
}
void opamp_user_trim_disable(uint32_t base)
{
OPAMP_CSR(base) &= ~OPAMP_CSR_USER_TRIM;
}
void opamp_pga_gain_select(uint32_t base, uint32_t gain)
{
OPAMP_CSR(base) &= ~(OPAMP_CSR_PGA_GAIN_MASK
<< OPAMP_CSR_PGA_GAIN_SHIFT);
OPAMP_CSR(base) |= gain << OPAMP_CSR_PGA_GAIN_SHIFT;
}
void opamp_vp_select(uint32_t base, uint32_t vp)
{
OPAMP_CSR(base) &= ~(OPAMP_CSR_VP_SEL_MASK
<< OPAMP_CSR_VP_SEL_SHIFT);
OPAMP_CSR(base) |= vp << OPAMP_CSR_VP_SEL_SHIFT;
}
void opamp_vm_select(uint32_t base, uint32_t vm)
{
OPAMP_CSR(base) &= ~(OPAMP_CSR_VM_SEL_MASK
<< OPAMP_CSR_VM_SEL_SHIFT);
OPAMP_CSR(base) |= vm << OPAMP_CSR_VM_SEL_SHIFT;
}
/**@}*/

View File

@@ -0,0 +1,56 @@
/** @addtogroup opamp_file OPAMP peripheral API
* @ingroup peripheral_apis
*/
/*
* 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/opamp.h>
bool opamp_read_outcal(uint32_t base)
{
return (OPAMP_CSR(base) >> OPAMP_CSR_OUTCAL_SHIFT)
& OPAMP_CSR_OUTCAL_MASK;
}
void opamp_tcm_enable(uint32_t base)
{
OPAMP_CSR(base) |= OPAMP_CSR_TCM_EN;
}
void opamp_tcm_disable(uint32_t base)
{
OPAMP_CSR(base) &= ~OPAMP_CSR_TCM_EN;
}
void opamp_vps_select(uint32_t base, uint32_t vps)
{
OPAMP_CSR(base) &= ~(OPAMP_CSR_VPS_SEL_MASK
<< OPAMP_CSR_VPS_SEL_SHIFT);
OPAMP_CSR(base) |= vps << OPAMP_CSR_VPS_SEL_SHIFT;
}
void opamp_vms_select(uint32_t base, uint32_t vms)
{
OPAMP_CSR(base) &= ~(OPAMP_CSR_VMS_SEL_MASK
<< OPAMP_CSR_VMS_SEL_SHIFT);
OPAMP_CSR(base) |= vms << OPAMP_CSR_VMS_SEL_SHIFT;
}
/**@}*/

View File

@@ -0,0 +1,52 @@
/** @addtogroup opamp_file OPAMP peripheral API
* @ingroup peripheral_apis
*/
/*
* 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/opamp.h>
bool opamp_read_calout(uint32_t base)
{
return (OPAMP_CSR(base) >> OPAMP_CSR_CALOUT_SHIFT) &
OPAMP_CSR_CALOUT_MASK;
}
void opamp_high_speed_mode_enable(uint32_t base)
{
OPAMP_CSR(base) |= OPAMP_CSR_OPAHSM;
}
void opamp_high_speed_mode_disable(uint32_t base)
{
OPAMP_CSR(base) &= ~OPAMP_CSR_OPAHSM;
}
void opamp_output_set_internal(uint32_t base)
{
OPAMP_CSR(base) |= OPAMP_CSR_OPAINTOEN;
}
void opamp_output_set_external(uint32_t base)
{
OPAMP_CSR(base) &= ~OPAMP_CSR_OPAINTOEN;
}
/**@}*/

View File

@@ -0,0 +1,206 @@
/** @addtogroup pwr_file PWR peripheral API
@ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2012
Ken Sarkies <ksarkies@internode.on.net>
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Ken Sarkies <ksarkies@internode.on.net>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/pwr.h>
/*---------------------------------------------------------------------------*/
/** @brief Disable Backup Domain Write Protection.
This allows backup domain registers to be changed. These registers are write
protected after a reset.
*/
void pwr_disable_backup_domain_write_protect(void)
{
PWR_CR |= PWR_CR_DBP;
}
/*---------------------------------------------------------------------------*/
/** @brief Re-enable Backup Domain Write Protection.
This protects backup domain registers from inadvertent change.
*/
void pwr_enable_backup_domain_write_protect(void)
{
PWR_CR &= ~PWR_CR_DBP;
}
/*---------------------------------------------------------------------------*/
/** @brief Enable Power Voltage Detector.
This provides voltage level threshold detection. The result of detection is
provided in the power voltage detector output flag (see @ref pwr_voltage_high)
or by setting the EXTI16 interrupt (see datasheet for configuration details).
@param[in] pvd_level uint32_t. Taken from @ref pwr_pls.
*/
void pwr_enable_power_voltage_detect(uint32_t pvd_level)
{
PWR_CR &= ~PWR_CR_PLS_MASK;
PWR_CR |= (PWR_CR_PVDE | pvd_level);
}
/*---------------------------------------------------------------------------*/
/** @brief Disable Power Voltage Detector.
*/
void pwr_disable_power_voltage_detect(void)
{
PWR_CR &= ~PWR_CR_PVDE;
}
/*---------------------------------------------------------------------------*/
/** @brief Clear the Standby Flag.
This is set when the processor returns from a standby mode.
*/
void pwr_clear_standby_flag(void)
{
PWR_CR |= PWR_CR_CSBF;
}
/*---------------------------------------------------------------------------*/
/** @brief Clear the Wakeup Flag.
This is set when the processor receives a wakeup signal.
*/
void pwr_clear_wakeup_flag(void)
{
PWR_CR |= PWR_CR_CWUF;
}
/*---------------------------------------------------------------------------*/
/** @brief Set Standby Mode in Deep Sleep.
*/
void pwr_set_standby_mode(void)
{
PWR_CR |= PWR_CR_PDDS;
}
/*---------------------------------------------------------------------------*/
/** @brief Set Stop Mode in Deep Sleep.
*/
void pwr_set_stop_mode(void)
{
PWR_CR &= ~PWR_CR_PDDS;
}
/*---------------------------------------------------------------------------*/
/** @brief Voltage Regulator On in Stop Mode.
*/
void pwr_voltage_regulator_on_in_stop(void)
{
PWR_CR &= ~PWR_CR_LPDS;
}
/*---------------------------------------------------------------------------*/
/** @brief Voltage Regulator Low Power in Stop Mode.
*/
void pwr_voltage_regulator_low_power_in_stop(void)
{
PWR_CR |= PWR_CR_LPDS;
}
/*---------------------------------------------------------------------------*/
/** @brief Enable Wakeup Pin.
The wakeup pin is used for waking the processor from standby mode.
*/
void pwr_enable_wakeup_pin(void)
{
PWR_CSR |= PWR_CSR_EWUP;
}
/*---------------------------------------------------------------------------*/
/** @brief Release Wakeup Pin.
The wakeup pin is used for general purpose I/O.
*/
void pwr_disable_wakeup_pin(void)
{
PWR_CSR &= ~PWR_CSR_EWUP;
}
/*---------------------------------------------------------------------------*/
/** @brief Get Voltage Detector Output.
The voltage detector threshold must be set when the power voltage detector is
enabled, see @ref pwr_enable_power_voltage_detect.
@returns boolean: TRUE if the power voltage is above the preset voltage
threshold.
*/
bool pwr_voltage_high(void)
{
return !(PWR_CSR & PWR_CSR_PVDO);
}
/*---------------------------------------------------------------------------*/
/** @brief Get Standby Flag.
The standby flag is set when the processor returns from a standby state. It is
cleared by software (see @ref pwr_clear_standby_flag).
@returns boolean: TRUE if the processor was in standby state.
*/
bool pwr_get_standby_flag(void)
{
return PWR_CSR & PWR_CSR_SBF;
}
/*---------------------------------------------------------------------------*/
/** @brief Get Wakeup Flag.
The wakeup flag is set when a wakeup event has been received. It is
cleared by software (see @ref pwr_clear_wakeup_flag).
@returns boolean: TRUE if a wakeup event was received.
*/
bool pwr_get_wakeup_flag(void)
{
return PWR_CSR & PWR_CSR_WUF;
}
/**@}*/

View File

@@ -0,0 +1,49 @@
/** @addtogroup pwr_file PWR peripheral API
* @ingroup peripheral_apis
*
* @author @htmlonly &copy; @endhtmlonly 2012 Karl Palsson <karlp@tweak.net.au>
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/pwr.h>
#include <libopencm3/stm32/rcc.h>
void pwr_set_vos_scale(enum pwr_vos_scale scale)
{
/* You are not allowed to write zeros here, don't try and optimize! */
uint32_t reg = PWR_CR;
reg &= ~(PWR_CR_VOS_MASK);
switch (scale) {
case PWR_SCALE1:
reg |= PWR_CR_VOS_RANGE1;
break;
case PWR_SCALE2:
reg |= PWR_CR_VOS_RANGE2;
break;
case PWR_SCALE3:
reg |= PWR_CR_VOS_RANGE3;
break;
}
PWR_CR = reg;
}
/**@}*/

View File

@@ -0,0 +1,12 @@
#include <libopencm3/stm32/quadspi.h>
void quadspi_enable(void)
{
QUADSPI_CR |= QUADSPI_CR_EN;
}
void quadspi_disable(void)
{
QUADSPI_CR &= ~QUADSPI_CR_EN;
}

View File

@@ -0,0 +1,288 @@
/** @addtogroup rcc_file RCC peripheral API
* @ingroup peripheral_apis
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2013 Frantisek Burian <bufran@seznam.cz>
* .. file is merged from many other copyrighted files of stm32 family
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/rcc.h>
/*---------------------------------------------------------------------------*/
/** @brief RCC Enable Peripheral Clocks.
*
* Enable the clock on particular peripherals. There are three registers
* involved, each one controlling the enabling of clocks associated with the
* AHB, APB1 and APB2 respectively. Several peripherals could be enabled
* simultaneously <em>only if they are controlled by the same register</em>.
* @sa rcc_periph_clock_enable for a less error prone version, if you only
* need to enable a single peripheral.
*
* @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_AHBENR, from @ref rcc_ahbenr_en
* @li If register is RCC_APB1ENR, from @ref rcc_apb1enr_en
* @li If register is RCC_APB2ENR, from @ref rcc_apb2enr_en
*/
void rcc_peripheral_enable_clock(volatile uint32_t *reg, uint32_t en)
{
*reg |= en;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Disable Peripheral Clocks.
*
* Disable 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>.
* @sa rcc_periph_clock_disable for a less error prone version, if you only
* need to disable a single peripheral.
*
* @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_AHBENR, from @ref rcc_ahbenr_en
* @li If register is RCC_APB1ENR, from @ref rcc_apb1enr_en
* @li If register is RCC_APB2ENR, from @ref rcc_apb2enr_en
*/
void rcc_peripheral_disable_clock(volatile uint32_t *reg, uint32_t en)
{
*reg &= ~en;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Reset Peripherals.
*
* Reset particular peripherals. There are three registers involved, each one
* controlling reset of peripherals associated with the AHB, APB1 and APB2
* respectively. Several peripherals could be reset simultaneously <em>only if
* they are controlled by the same register</em>.
* @sa rcc_periph_reset_hold for a less error prone version, if you only
* need to reset a single peripheral.
* @sa rcc_periph_reset_pulse if you are only going to toggle reset anyway.
*
* @param[in] *reg Unsigned int32. Pointer to a Reset Register
* (either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR)
* @param[in] reset Unsigned int32. Logical OR of all resets.
* @li If register is RCC_AHBRSTR, from @ref rcc_ahbrstr_rst
* @li If register is RCC_APB1RSTR, from @ref rcc_apb1rstr_rst
* @li If register is RCC_APB2RSTR, from @ref rcc_apb2rstr_rst
*/
void rcc_peripheral_reset(volatile uint32_t *reg, uint32_t reset)
{
*reg |= reset;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Remove Reset on Peripherals.
*
* Remove the reset on particular peripherals. There are three registers
* involved, each one controlling reset of peripherals associated with the AHB,
* APB1 and APB2 respectively. Several peripherals could have the reset removed
* simultaneously <em>only if they are controlled by the same register</em>.
* @sa rcc_periph_reset_release for a less error prone version, if you only
* need to unreset a single peripheral.
* @sa rcc_periph_reset_pulse if you are only going to toggle reset anyway.
*
* @param[in] *reg Unsigned int32. Pointer to a Reset Register
* (either RCC_AHBENR, RCC_APB1ENR or RCC_APB2ENR)
* @param[in] clear_reset Unsigned int32. Logical OR of all resets to be
* removed:
* @li If register is RCC_AHBRSTR, from @ref rcc_ahbrstr_rst
* @li If register is RCC_APB1RSTR, from @ref rcc_apb1rstr_rst
* @li If register is RCC_APB2RSTR, from @ref rcc_apb2rstr_rst
*/
void rcc_peripheral_clear_reset(volatile uint32_t *reg, uint32_t clear_reset)
{
*reg &= ~clear_reset;
}
#define _RCC_REG(i) MMIO32(RCC_BASE + ((i) >> 5))
#define _RCC_BIT(i) (1 << ((i) & 0x1f))
/*---------------------------------------------------------------------------*/
/** @brief Enable Peripheral Clock in running mode.
*
* Enable the clock on particular peripheral.
*
* @param[in] clken rcc_periph_clken Peripheral RCC
*
* For available constants, see #rcc_periph_clken (RCC_UART1 for example)
*/
void rcc_periph_clock_enable(enum rcc_periph_clken clken)
{
_RCC_REG(clken) |= _RCC_BIT(clken);
}
/*---------------------------------------------------------------------------*/
/** @brief Disable Peripheral Clock in running mode.
* Disable the clock on particular peripheral.
*
* @param[in] clken rcc_periph_clken Peripheral RCC
*
* For available constants, see #rcc_periph_clken (RCC_UART1 for example)
*/
void rcc_periph_clock_disable(enum rcc_periph_clken clken)
{
_RCC_REG(clken) &= ~_RCC_BIT(clken);
}
/*---------------------------------------------------------------------------*/
/** @brief Reset Peripheral, pulsed
*
* Reset particular peripheral, and restore to working state.
*
* @param[in] rst rcc_periph_rst Peripheral reset
*
* For available constants, see #rcc_periph_rst (RST_UART1 for example)
*/
void rcc_periph_reset_pulse(enum rcc_periph_rst rst)
{
_RCC_REG(rst) |= _RCC_BIT(rst);
_RCC_REG(rst) &= ~_RCC_BIT(rst);
}
/*---------------------------------------------------------------------------*/
/** @brief Reset Peripheral, hold
*
* Reset particular peripheral, and hold in reset state.
*
* @param[in] rst rcc_periph_rst Peripheral reset
*
* For available constants, see #rcc_periph_rst (RST_UART1 for example)
*/
void rcc_periph_reset_hold(enum rcc_periph_rst rst)
{
_RCC_REG(rst) |= _RCC_BIT(rst);
}
/*---------------------------------------------------------------------------*/
/** @brief Reset Peripheral, release
*
* Restore peripheral from reset state to working state.
*
* @param[in] rst rcc_periph_rst Peripheral reset
*
* For available constants, see #rcc_periph_rst (RST_UART1 for example)
*/
void rcc_periph_reset_release(enum rcc_periph_rst rst)
{
_RCC_REG(rst) &= ~_RCC_BIT(rst);
}
/** @brief Select the source of Microcontroller Clock Output
*
* Exact sources available depend on your target. On devices with multiple
* MCO pins, this function controls MCO1
*
* @param[in] mcosrc the unshifted source bits
*/
void rcc_set_mco(uint32_t mcosrc)
{
RCC_CFGR = (RCC_CFGR & ~(RCC_CFGR_MCO_MASK << RCC_CFGR_MCO_SHIFT)) |
(mcosrc << RCC_CFGR_MCO_SHIFT);
}
/**
* 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 Oscillator ID. Only HSE and LSE have effect.
*/
void rcc_osc_bypass_enable(enum rcc_osc osc)
{
switch (osc) {
case RCC_HSE:
RCC_CR |= RCC_CR_HSEBYP;
break;
case RCC_LSE:
#ifdef RCC_CSR_LSEBYP
RCC_CSR |= RCC_CSR_LSEBYP;
#else
RCC_BDCR |= RCC_BDCR_LSEBYP;
#endif
break;
default:
/* Do nothing, only HSE/LSE allowed here. */
break;
}
}
/**
* 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 Oscillator ID. Only HSE and LSE have effect.
*/
void rcc_osc_bypass_disable(enum rcc_osc osc)
{
switch (osc) {
case RCC_HSE:
RCC_CR &= ~RCC_CR_HSEBYP;
break;
case RCC_LSE:
#ifdef RCC_CSR_LSEBYP
RCC_CSR &= ~RCC_CSR_LSEBYP;
#else
RCC_BDCR &= ~RCC_BDCR_LSEBYP;
#endif
break;
default:
/* Do nothing, only HSE/LSE allowed here. */
break;
}
}
/* This is a helper to calculate dividers that go 2/4/8/16/64/128/256/512.
* These dividers also use the top bit as an "enable". This is typically
* used for AHB and other system clock prescaler. */
uint16_t rcc_get_div_from_hpre(uint8_t div_val) {
if (div_val < 0x8) {
return 1;
} else if (div_val <= 0x0b /* DIV16 */) {
return (1U << (div_val - 7));
} else {
return (1U << (div_val - 6));
}
}
/**@}*/
#undef _RCC_REG
#undef _RCC_BIT

View File

@@ -0,0 +1,121 @@
/** @addtogroup rng_file RNG peripheral API
* @ingroup peripheral_apis
*
* This library supports "version 1" of the random number generator
* peripheral (RNG) in the STM32 series of ARM Cortex Microcontrollers
* by ST Microelectronics. This is a common peripheral available on multiple
* devices in the family.
*
* 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/rng.h>
/**@{*/
/** Disable the Random Number Generator peripheral.
*/
void rng_disable(void)
{
RNG_CR &= ~RNG_CR_RNGEN;
}
/** Enable the Random Number Generator peripheral.
*/
void rng_enable(void)
{
RNG_CR |= RNG_CR_RNGEN;
}
/** Enable the Random Number Generator error interrupt.
*/
void rng_interrupt_enable(void)
{
RNG_CR |= RNG_CR_IE;
}
/** Disable the Random Number Generator error interrupt.
*/
void rng_interrupt_disable(void)
{
RNG_CR &= ~RNG_CR_IE;
}
/** Randomizes a number (non-blocking).
* Can fail if a clock error or seed error is detected. Consult the Reference
* Manual, but "try again", potentially after resetting the peripheral
* @param rand_nr pointer to a uint32_t that will be randomized.
* @returns true on success, pointer is only written to on success
* @sa rng_get_random_blocking
*/
bool rng_get_random(uint32_t *rand_nr)
{
/* Check for errors */
if (RNG_SR & (RNG_SR_CECS | RNG_SR_SECS)) {
return false;
}
/* data ready */
if (!(RNG_SR & RNG_SR_DRDY)) {
return false;
}
*rand_nr = RNG_DR;
return true;
}
/**
* Get a random number and block until it works.
* Unless you have a clock problem, this should always return "promptly"
* If you have a clock problem, you will wait here forever!
* Check device RM for clock requirements (usually fRNGCLK > fHCLK/16 or
* fRNGCLK > fHCLK/32
* @returns a random 32bit number
*/
uint32_t rng_get_random_blocking(void)
{
uint32_t rv;
bool done;
do {
if (RNG_SR & RNG_SR_SEIS) {
RNG_SR = RNG_SR & ~RNG_SR_SEIS;
for (int i = 12; i != 0; i--) {
rv = RNG_DR;
}
RNG_CR &= ~RNG_CR_RNGEN;
RNG_CR |= RNG_CR_RNGEN;
}
if (RNG_SR & RNG_SR_CEIS) {
RNG_SR = RNG_SR & ~RNG_SR_CEIS;
}
done = rng_get_random(&rv);
} while (!done);
return rv;
}
/**@}*/

View File

@@ -0,0 +1,338 @@
/** @addtogroup rtc_file RTC peripheral API
@ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2012 Karl Palsson <karlp@tweak.net.au>
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/rtc.h>
static uint8_t _rtc_dec_to_bcd(uint8_t dec)
{
return ((dec / 10) << 4) | (dec % 10);
}
/*---------------------------------------------------------------------------*/
/** @brief Set RTC prescalars.
This sets the RTC synchronous and asynchronous prescalars.
*/
void rtc_set_prescaler(uint32_t sync, uint32_t async)
{
/*
* Even if only one of the two fields needs to be changed,
* 2 separate write accesses must be performed to the RTC_PRER register.
*/
RTC_PRER = (sync & RTC_PRER_PREDIV_S_MASK);
RTC_PRER |= (async << RTC_PRER_PREDIV_A_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief Wait for RTC registers to be synchronised with the APB1 bus
Time and Date are accessed through shadow registers which must be synchronized
*/
void rtc_wait_for_synchro(void)
{
/* Unlock RTC registers */
RTC_WPR = 0xca;
RTC_WPR = 0x53;
RTC_ISR &= ~(RTC_ISR_RSF);
while (!(RTC_ISR & RTC_ISR_RSF));
/* disable write protection again */
RTC_WPR = 0xff;
}
/*---------------------------------------------------------------------------*/
/** @brief Unlock write access to the RTC registers
*/
void rtc_unlock(void)
{
RTC_WPR = 0xca;
RTC_WPR = 0x53;
}
/*---------------------------------------------------------------------------*/
/** @brief Lock write access to the RTC registers
*/
void rtc_lock(void)
{
RTC_WPR = 0xff;
}
/*---------------------------------------------------------------------------*/
/** @brief Sets the wakeup time auto-reload value
*/
void rtc_set_wakeup_time(uint16_t wkup_time, uint8_t rtc_cr_wucksel)
{
/* FTFM:
* The following sequence is required to configure or change the wakeup
* timer auto-reload value (WUT[15:0] in RTC_WUTR):
* 1. Clear WUTE in RTC_CR to disable the wakeup timer.
*/
RTC_CR &= ~RTC_CR_WUTE;
/* 2. Poll WUTWF until it is set in RTC_ISR to make sure the access to
* wakeup auto-reload counter and to WUCKSEL[2:0] bits is allowed.
* It takes around 2 RTCCLK clock cycles (due to clock
* synchronization).
*/
while (!((RTC_ISR) & (RTC_ISR_WUTWF)));
/* 3. Program the wakeup auto-reload value WUT[15:0], and the wakeup
* clock selection (WUCKSEL[2:0] bits in RTC_CR).Set WUTE in RTC_CR
* to enable the timer again. The wakeup timer restarts
* down-counting.
*/
RTC_WUTR = wkup_time;
RTC_CR &= ~(RTC_CR_WUCLKSEL_MASK << RTC_CR_WUCLKSEL_SHIFT);
RTC_CR |= (rtc_cr_wucksel << RTC_CR_WUCLKSEL_SHIFT);
RTC_CR |= RTC_CR_WUTE;
}
/*---------------------------------------------------------------------------*/
/** @brief Clears the wakeup flag
@details This function should be called first in the rtc_wkup_isr()
*/
void rtc_clear_wakeup_flag(void)
{
RTC_ISR &= ~RTC_ISR_WUTF;
}
/*---------------------------------------------------------------------------*/
/** @brief Sets the initialization flag
@details Requires unlocking backup domain write protection (PWR_CR_DBP)
*/
void rtc_set_init_flag(void)
{
RTC_ISR |= RTC_ISR_INIT;
}
/*---------------------------------------------------------------------------*/
/** @brief Clears (resets) the initialization flag
@details Requires unlocking backup domain write protection (PWR_CR_DBP)
*/
void rtc_clear_init_flag(void)
{
RTC_ISR &= ~RTC_ISR_INIT;
}
/*---------------------------------------------------------------------------*/
/** @brief Returns if the RTC_ISR init flag RTC_ISR_INITF is set
@details Requires unlocking backup domain write protection (PWR_CR_DBP)
*/
bool rtc_init_flag_is_ready(void)
{
return (RTC_ISR & RTC_ISR_INITF);
}
/*---------------------------------------------------------------------------*/
/** @brief Waits infinitely for initialization flag to be set in RTC_ISR
@details Requires unlocking backup domain write protection (PWR_CR_DBP)
*/
void rtc_wait_for_init_ready(void)
{
while (!rtc_init_flag_is_ready());
}
/*---------------------------------------------------------------------------*/
/** @brief Sets the bypass shadow bit in RTC_CR
@details Requires unlocking backup domain write protection (PWR_CR_DBP)
*/
void rtc_enable_bypass_shadow_register(void)
{
RTC_CR |= RTC_CR_BYPSHAD;
}
/*---------------------------------------------------------------------------*/
/** @brief Clears the bypass shadow bit in RTC_CR
@details Requires unlocking backup domain write protection (PWR_CR_DBP)
*/
void rtc_disable_bypass_shadow_register(void)
{
RTC_CR &= ~RTC_CR_BYPSHAD;
}
/*---------------------------------------------------------------------------*/
/** @brief Sets the RTC control register hour format to AM (24h)
@details Requires unlocking backup domain write protection (PWR_CR_DBP)
*/
void rtc_set_am_format(void)
{
RTC_CR &= ~RTC_CR_FMT;
}
/*---------------------------------------------------------------------------*/
/** @brief Sets the RTC control register hour format to PM (12h)
@details Requires unlocking backup domain write protection (PWR_CR_DBP)
*/
void rtc_set_pm_format(void)
{
RTC_CR |= RTC_CR_FMT;
}
/*---------------------------------------------------------------------------*/
/** @brief Sets the RTC BCD calendar year value
@details Requires unlocking the RTC write-protection (RTC_WPR)
The year value should only be the abbreviated year tens, meaning if 2021 is
desired pass in only 21.
*/
void rtc_calendar_set_year(uint8_t year)
{
uint8_t bcd_year = _rtc_dec_to_bcd(year);
RTC_DR &= ~(RTC_DR_YT_MASK << RTC_DR_YT_SHIFT | RTC_DR_YU_MASK << RTC_DR_YU_SHIFT);
RTC_DR |= (((bcd_year >> 4) & RTC_DR_YT_MASK) << RTC_DR_YT_SHIFT) |
((bcd_year & RTC_DR_YU_MASK) << RTC_DR_YU_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief Sets the RTC BCD calendar weekday
@details Requires unlocking the RTC write-protection (RTC_WPR)
*/
void rtc_calendar_set_weekday(enum rtc_weekday rtc_dr_wdu)
{
RTC_DR &= ~(RTC_DR_WDU_MASK << RTC_DR_WDU_SHIFT);
RTC_DR |= (rtc_dr_wdu << RTC_DR_WDU_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief Sets the RTC BCD calendar month value
@details Requires unlocking the RTC write-protection (RTC_WPR)
*/
void rtc_calendar_set_month(uint8_t month)
{
uint8_t bcd_month = _rtc_dec_to_bcd(month);
RTC_DR &= ~(RTC_DR_MT_MASK << RTC_DR_MT_SHIFT | RTC_DR_MU_MASK << RTC_DR_MU_SHIFT);
RTC_DR |= (((bcd_month >> 4) & RTC_DR_MT_MASK) << RTC_DR_MT_SHIFT) |
((bcd_month & RTC_DR_MU_MASK) << RTC_DR_MU_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief Sets the RTC BCD calendar day value
@details Requires unlocking the RTC write-protection (RTC_WPR)
*/
void rtc_calendar_set_day(uint8_t day)
{
uint8_t bcd_day = _rtc_dec_to_bcd(day);
RTC_DR &= ~(RTC_DR_DT_MASK << RTC_DR_DT_SHIFT | RTC_DR_DU_MASK << RTC_DR_DU_SHIFT);
RTC_DR |= (((bcd_day >> 4) & RTC_DR_DT_MASK) << RTC_DR_DT_SHIFT) |
((bcd_day & RTC_DR_DU_MASK) << RTC_DR_DU_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief Sets the RTC BCD calendar value
@details Requires unlocking the RTC write-protection (RTC_WPR)
The year value should only be the abbreviated year tens, meaning if 2021 is
desired pass in only 21.
*/
void rtc_calendar_set_date(uint8_t year, uint8_t month, uint8_t day, enum rtc_weekday rtc_dr_wdu)
{
rtc_calendar_set_year(year);
rtc_calendar_set_month(month);
rtc_calendar_set_weekday(rtc_dr_wdu);
rtc_calendar_set_day(day);
}
/*---------------------------------------------------------------------------*/
/** @brief Sets the RTC BCD time hour value
@details Requires unlocking the RTC write-protection (RTC_WPR)
Pass true to use_am_notation to use 24-hour input time; pass false to
use_am_notation to use 12-hour (AM/PM) input time
*/
void rtc_time_set_hour(uint8_t hour, bool use_am_notation)
{
if (use_am_notation) {
RTC_TR &= ~(RTC_TR_PM);
} else {
RTC_TR |= RTC_TR_PM;
}
uint8_t bcd_hour = _rtc_dec_to_bcd(hour);
RTC_TR &= ~(RTC_TR_HT_MASK << RTC_TR_HT_SHIFT | RTC_TR_HU_MASK << RTC_TR_HU_SHIFT);
RTC_TR |= (((bcd_hour >> 4) & RTC_TR_HT_MASK) << RTC_TR_HT_SHIFT) |
((bcd_hour & RTC_TR_HU_MASK) << RTC_TR_HU_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief Sets the RTC BCD time minute value
@details Requires unlocking the RTC write-protection (RTC_WPR)
*/
void rtc_time_set_minute(uint8_t minute)
{
uint8_t bcd_minute = _rtc_dec_to_bcd(minute);
RTC_TR &= ~(RTC_TR_MNT_MASK << RTC_TR_MNT_SHIFT | RTC_TR_MNU_MASK << RTC_TR_MNU_SHIFT);
RTC_TR |= (((bcd_minute >> 4) & RTC_TR_MNT_MASK) << RTC_TR_MNT_SHIFT) |
((bcd_minute & RTC_TR_MNU_MASK) << RTC_TR_MNU_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief Sets the RTC BCD time second value
@details Requires unlocking the RTC write-protection (RTC_WPR)
*/
void rtc_time_set_second(uint8_t second)
{
uint8_t bcd_second = _rtc_dec_to_bcd(second);
RTC_TR &= ~(RTC_TR_ST_MASK << RTC_TR_ST_SHIFT | RTC_TR_SU_MASK << RTC_TR_SU_SHIFT);
RTC_TR |= (((bcd_second >> 4) & RTC_TR_ST_MASK) << RTC_TR_ST_SHIFT) |
((bcd_second & RTC_TR_SU_MASK) << RTC_TR_SU_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief Sets the RTC BCD time
@details Requires unlocking the RTC write-protection (RTC_WPR)
*/
void rtc_time_set_time(uint8_t hour, uint8_t minute, uint8_t second, bool use_am_notation)
{
rtc_time_set_hour(hour, use_am_notation);
rtc_time_set_minute(minute);
rtc_time_set_second(second);
}
/**@}*/

View File

@@ -0,0 +1,681 @@
/** @addtogroup spi_file SPI peripheral API
* @ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2009
Uwe Hermann <uwe@hermann-uwe.de>
@author @htmlonly &copy; @endhtmlonly 2012
Ken Sarkies <ksarkies@internode.on.net>
Devices can have up to three SPI peripherals. The common 4-wire full-duplex
mode of operation is supported, along with 3-wire variants using unidirectional
communication modes or half-duplex bidirectional communication. A variety of
options allows many of the SPI variants to be supported. Multimaster operation
is also supported. A CRC can be generated and checked in hardware.
@note Some JTAG pins need to be remapped if SPI is to be used.
@note The I2S protocol shares the SPI hardware so the two protocols cannot be
used at the same time on the same peripheral.
Example: Clk/4, positive clock polarity, leading edge trigger, 8-bit words,
LSB first.
@code
spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_4, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_LSBFIRST);
spi_write(SPI1, 0x55); // 8-bit write
spi_write(SPI1, 0xaa88); // 16-bit write
reg8 = spi_read(SPI1); // 8-bit read
reg16 = spi_read(SPI1); // 16-bit read
@endcode
@todo need additional functions to aid ISRs in retrieving status
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/spi.h>
#include <libopencm3/stm32/rcc.h>
/**@{*/
/* TODO: Error handling? */
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable.
The SPI peripheral is enabled.
@todo Error handling?
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_SPE; /* Enable SPI. */
}
/* TODO: Error handling? */
/*---------------------------------------------------------------------------*/
/** @brief SPI Disable.
The SPI peripheral is disabled.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable(uint32_t spi)
{
uint32_t reg32;
reg32 = SPI_CR1(spi);
reg32 &= ~(SPI_CR1_SPE); /* Disable SPI. */
SPI_CR1(spi) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Clean Disable.
Disable the SPI peripheral according to the procedure in section 23.3.8 of the
reference manual. This prevents corruption of any ongoing transfers and
prevents the BSY flag from becoming unreliable.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@returns data Unsigned int16. 8 or 16 bit data from final read.
*/
uint16_t spi_clean_disable(uint32_t spi)
{
/* Wait to receive last data */
while (!(SPI_SR(spi) & SPI_SR_RXNE));
uint16_t data = SPI_DR(spi);
/* Wait to transmit last data */
while (!(SPI_SR(spi) & SPI_SR_TXE));
/* Wait until not busy */
while (SPI_SR(spi) & SPI_SR_BSY);
SPI_CR1(spi) &= ~SPI_CR1_SPE;
return data;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Data Write.
Data is written to the SPI interface.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@param[in] data Unsigned int16. 8 or 16 bit data to be written.
*/
void spi_write(uint32_t spi, uint16_t data)
{
/* Write data (8 or 16 bits, depending on DFF) into DR. */
SPI_DR(spi) = data;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Data Write with Blocking.
Data is written to the SPI interface after the previous write transfer has
finished.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@param[in] data Unsigned int16. 8 or 16 bit data to be written.
*/
void spi_send(uint32_t spi, uint16_t data)
{
/* Wait for transfer finished. */
while (!(SPI_SR(spi) & SPI_SR_TXE));
/* Write data (8 or 16 bits, depending on DFF) into DR. */
SPI_DR(spi) = data;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Data Read.
Data is read from the SPI interface after the incoming transfer has finished.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@returns data Unsigned int16. 8 or 16 bit data.
*/
uint16_t spi_read(uint32_t spi)
{
/* Wait for transfer finished. */
while (!(SPI_SR(spi) & SPI_SR_RXNE));
/* Read the data (8 or 16 bits, depending on DFF bit) from DR. */
return SPI_DR(spi);
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Data Write and Read Exchange.
Data is written to the SPI interface, then a read is done after the incoming
transfer has finished.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@param[in] data Unsigned int16. 8 or 16 bit data to be written.
@returns data Unsigned int16. 8 or 16 bit data.
*/
uint16_t spi_xfer(uint32_t spi, uint16_t data)
{
spi_write(spi, data);
/* Wait for transfer finished. */
while (!(SPI_SR(spi) & SPI_SR_RXNE));
/* Read the data (8 or 16 bits, depending on DFF bit) from DR. */
return SPI_DR(spi);
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Bidirectional Simplex Mode.
The SPI peripheral is set for bidirectional transfers in two-wire simplex mode
(using a clock wire and a bidirectional data wire).
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_bidirectional_mode(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_BIDIMODE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Unidirectional Mode.
The SPI peripheral is set for unidirectional transfers. This is used in full
duplex mode or when the SPI is placed in two-wire simplex mode that uses a
clock wire and a unidirectional data wire.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_unidirectional_mode(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_BIDIMODE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Bidirectional Simplex Receive Only Mode.
The SPI peripheral is set for bidirectional transfers in two-wire simplex mode
(using a clock wire and a bidirectional data wire), and is placed in a receive
state.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_bidirectional_receive_only_mode(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_BIDIMODE;
SPI_CR1(spi) &= ~SPI_CR1_BIDIOE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Bidirectional Simplex Receive Only Mode.
The SPI peripheral is set for bidirectional transfers in two-wire simplex mode
(using a clock wire and a bidirectional data wire), and is placed in a transmit
state.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_bidirectional_transmit_only_mode(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_BIDIMODE;
SPI_CR1(spi) |= SPI_CR1_BIDIOE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable the CRC.
The SPI peripheral is set to use a CRC field for transmit and receive.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable_crc(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_CRCEN;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Disable the CRC.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable_crc(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_CRCEN;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Next Transmit is a Data Word
The next transmission to take place is a data word from the transmit buffer.
This must be called before transmission to distinguish between sending
of a data or CRC word.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_next_tx_from_buffer(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_CRCNEXT;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Next Transmit is a CRC Word
The next transmission to take place is a crc word from the hardware crc unit.
This must be called before transmission to distinguish between sending
of a data or CRC word.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_next_tx_from_crc(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_CRCNEXT;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Full Duplex (3-wire) Mode
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_full_duplex_mode(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_RXONLY;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Receive Only Mode for Simplex (2-wire) Unidirectional
Transfers
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_receive_only_mode(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_RXONLY;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Disable Slave Management by Hardware
In slave mode the NSS hardware input is used as a select enable for the slave.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable_software_slave_management(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_SSM;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable Slave Management by Software
In slave mode the NSS hardware input is replaced by an internal software
enable/disable of the slave (@ref spi_set_nss_high).
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable_software_slave_management(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_SSM;
/* allow slave select to be an input */
SPI_CR2(spi) &= ~SPI_CR2_SSOE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the Software NSS Signal High
In slave mode, and only when software slave management is used, this replaces
the NSS signal with a slave select enable signal.
@todo these should perhaps be combined with an SSM enable as it is meaningless
otherwise
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_nss_high(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_SSI;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the Software NSS Signal Low
In slave mode, and only when software slave management is used, this replaces
the NSS signal with a slave select disable signal.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_nss_low(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_SSI;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set to Send LSB First
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_send_lsb_first(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_LSBFIRST;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set to Send MSB First
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_send_msb_first(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_LSBFIRST;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the Baudrate Prescaler
@todo Why is this specification different to the spi_init_master baudrate
values?
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@param[in] baudrate Unsigned int8. Baudrate prescale value @ref spi_br_pre.
*/
void spi_set_baudrate_prescaler(uint32_t spi, uint8_t baudrate)
{
uint32_t reg32;
if (baudrate > 7) {
return;
}
reg32 = (SPI_CR1(spi) & 0xffc7); /* Clear bits [5:3]. */
reg32 |= (baudrate << 3);
SPI_CR1(spi) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set to Master Mode
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_master_mode(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_MSTR;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set to Slave Mode
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_slave_mode(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_MSTR;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the Clock Polarity to High when Idle
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@sa spi_set_clock_polarity_0
*/
void spi_set_clock_polarity_1(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_CPOL;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the Clock Polarity to Low when Idle
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@sa spi_set_clock_polarity_1
*/
void spi_set_clock_polarity_0(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_CPOL;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the Clock Phase to Capture on Trailing Edge
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@sa spi_set_clock_phase_0
*/
void spi_set_clock_phase_1(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_CPHA;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the Clock Phase to Capture on Leading Edge
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@sa spi_set_clock_phase_1
*/
void spi_set_clock_phase_0(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_CPHA;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable the Transmit Buffer Empty Interrupt
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable_tx_buffer_empty_interrupt(uint32_t spi)
{
SPI_CR2(spi) |= SPI_CR2_TXEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Disable the Transmit Buffer Empty Interrupt
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable_tx_buffer_empty_interrupt(uint32_t spi)
{
SPI_CR2(spi) &= ~SPI_CR2_TXEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable the Receive Buffer Ready Interrupt
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable_rx_buffer_not_empty_interrupt(uint32_t spi)
{
SPI_CR2(spi) |= SPI_CR2_RXNEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Disable the Receive Buffer Ready Interrupt
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable_rx_buffer_not_empty_interrupt(uint32_t spi)
{
SPI_CR2(spi) &= ~SPI_CR2_RXNEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable the Error Interrupt
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable_error_interrupt(uint32_t spi)
{
SPI_CR2(spi) |= SPI_CR2_ERRIE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Disable the Error Interrupt
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable_error_interrupt(uint32_t spi)
{
SPI_CR2(spi) &= ~SPI_CR2_ERRIE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the NSS Pin as an Output
Normally used in master mode to allows the master to place all devices on the
SPI bus into slave mode. Multimaster mode is not possible.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable_ss_output(uint32_t spi)
{
SPI_CR2(spi) |= SPI_CR2_SSOE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the NSS Pin as an Input
In master mode this allows the master to sense the presence of other masters. If
NSS is then pulled low the master is placed into slave mode. In slave mode NSS
becomes a slave enable.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable_ss_output(uint32_t spi)
{
SPI_CR2(spi) &= ~SPI_CR2_SSOE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable Transmit Transfers via DMA
This allows transmissions to proceed unattended using DMA to move data to the
transmit buffer as it becomes available. The DMA channels provided for each
SPI peripheral are given in the Technical Manual DMA section.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable_tx_dma(uint32_t spi)
{
SPI_CR2(spi) |= SPI_CR2_TXDMAEN;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Disable Transmit Transfers via DMA
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable_tx_dma(uint32_t spi)
{
SPI_CR2(spi) &= ~SPI_CR2_TXDMAEN;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable Receive Transfers via DMA
This allows received data streams to proceed unattended using DMA to move data
from the receive buffer as data becomes available. The DMA channels provided
for each SPI peripheral are given in the Technical Manual DMA section.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable_rx_dma(uint32_t spi)
{
SPI_CR2(spi) |= SPI_CR2_RXDMAEN;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Disable Receive Transfers via DMA
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable_rx_dma(uint32_t spi)
{
SPI_CR2(spi) &= ~SPI_CR2_RXDMAEN;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Standard Mode selection
@details Set SPI standard Modes
Mode | CPOL | CPHA
---- | ---- | ----
0 | 0 | 0
1 | 0 | 1
2 | 1 | 0
3 | 1 | 1
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@param[in] mode Unsigned int8. Standard SPI mode (0, 1, 2, 3)
@sa spi_set_clock_phase_0 spi_set_clock_phase_1
@sa spi_set_clock_polarity_0 spi_set_clock_polarity_1
*/
void spi_set_standard_mode(uint32_t spi, uint8_t mode)
{
if (mode > 3) {
return;
}
uint32_t reg32 = SPI_CR1(spi) & ~(SPI_CR1_CPOL | SPI_CR1_CPHA);
SPI_CR1(spi) = reg32 | mode;
}
/**@}*/

View File

@@ -0,0 +1,127 @@
/** @addtogroup spi_file SPI peripheral API
* @ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2009
Uwe Hermann <uwe@hermann-uwe.de>
@author @htmlonly &copy; @endhtmlonly 2012
Ken Sarkies <ksarkies@internode.on.net>
Devices can have up to three SPI peripherals. The common 4-wire full-duplex
mode of operation is supported, along with 3-wire variants using unidirectional
communication modes or half-duplex bidirectional communication. A variety of
options allows many of the SPI variants to be supported. Multimaster operation
is also supported. A CRC can be generated and checked in hardware.
@note Some JTAG pins need to be remapped if SPI is to be used.
@note The I2S protocol shares the SPI hardware so the two protocols cannot be
used at the same time on the same peripheral.
Example: Clk/4, positive clock polarity, leading edge trigger, 8-bit words,
LSB first.
@code
spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_4, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_LSBFIRST);
spi_write(SPI1, 0x55); // 8-bit write
spi_write(SPI1, 0xaa88); // 16-bit write
reg8 = spi_read(SPI1); // 8-bit read
reg16 = spi_read(SPI1); // 16-bit read
@endcode
@todo need additional functions to aid ISRs in retrieving status
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/spi.h>
#include <libopencm3/stm32/rcc.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief Configure the SPI as Master.
The SPI peripheral is configured as a master with communication parameters
baudrate, data format 8/16 bits, frame format lsb/msb first, clock polarity
and phase. The SPI enable, CRC enable and CRC next controls are not affected.
These must be controlled separately.
To support multiple masters (dynamic switching between master and slave)
you must set SSOE to 0 and select either software or hardware control of
the NSS pin.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@param[in] br Unsigned int32. Baudrate @ref spi_baudrate.
@param[in] cpol Unsigned int32. Clock polarity @ref spi_cpol.
@param[in] cpha Unsigned int32. Clock Phase @ref spi_cpha.
@param[in] dff Unsigned int32. Data frame format 8/16 bits @ref spi_dff.
@param[in] lsbfirst Unsigned int32. Frame format lsb/msb first @ref
spi_lsbfirst.
@returns int. Error code.
*/
int spi_init_master(uint32_t spi, uint32_t br, uint32_t cpol, uint32_t cpha,
uint32_t dff, uint32_t lsbfirst)
{
uint32_t reg32 = SPI_CR1(spi);
/* Reset all bits omitting SPE, CRCEN and CRCNEXT bits. */
reg32 &= SPI_CR1_SPE | SPI_CR1_CRCEN | SPI_CR1_CRCNEXT;
reg32 |= SPI_CR1_MSTR; /* Configure SPI as master. */
reg32 |= br; /* Set baud rate bits. */
reg32 |= cpol; /* Set CPOL value. */
reg32 |= cpha; /* Set CPHA value. */
reg32 |= dff; /* Set data format (8 or 16 bits). */
reg32 |= lsbfirst; /* Set frame format (LSB- or MSB-first). */
SPI_CR2(spi) |= SPI_CR2_SSOE; /* common case */
SPI_CR1(spi) = reg32;
return 0;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Data Frame Format to 8 bits
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_dff_8bit(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_DFF;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Data Frame Format to 16 bits
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_dff_16bit(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_DFF;
}
/**@}*/

View File

@@ -0,0 +1,68 @@
/** @addtogroup spi_file SPI peripheral API
* @ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2009
Uwe Hermann <uwe@hermann-uwe.de>
@author @htmlonly &copy; @endhtmlonly 2012
Ken Sarkies <ksarkies@internode.on.net>
@author @htmlonly &copy; @endhtmlonly 2018
Guillaume Revaillot <revaillot@archos.com>
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/spi.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Frame Format to TI
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_frf_ti(uint32_t spi)
{
SPI_CR2(spi) |= SPI_CR2_FRF;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Frame Format to Motorola
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_frf_motorola(uint32_t spi)
{
SPI_CR2(spi) &= ~SPI_CR2_FRF;
}
#define SPI_CR2_FRF (1 << 4)
#define SPI_CR2_FRF_MOTOROLA_MODE (0 << 4)
#define SPI_CR2_FRF_TI_MODE (1 << 4)
/* --- SPI_SR values ------------------------------------------------------- */
/* FRE / TIFRFE: TI frame format error */
#define SPI_SR_TIFRFE (1 << 8) //F2
#define SPI_SR_FRE (1 << 8) //others
/**@}*/

View File

@@ -0,0 +1,169 @@
/** @addtogroup spi_file SPI peripheral API
* @ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2009
Uwe Hermann <uwe@hermann-uwe.de>
@author @htmlonly &copy; @endhtmlonly 2012
Ken Sarkies <ksarkies@internode.on.net>
Devices can have up to three SPI peripherals. The common 4-wire full-duplex
mode of operation is supported, along with 3-wire variants using unidirectional
communication modes or half-duplex bidirectional communication. A variety of
options allows many of the SPI variants to be supported. Multimaster operation
is also supported. A CRC can be generated and checked in hardware.
@note Some JTAG pins need to be remapped if SPI is to be used.
@note The I2S protocol shares the SPI hardware so the two protocols cannot be
used at the same time on the same peripheral.
Example: Clk/4, positive clock polarity, leading edge trigger, 8-bit words,
LSB first.
@code
spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_4, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_CRCL_8BIT, SPI_CR1_LSBFIRST);
spi_write(SPI1, 0x55); // 8-bit write
spi_write(SPI1, 0xaa88); // 16-bit write
reg8 = spi_read(SPI1); // 8-bit read
reg16 = spi_read(SPI1); // 16-bit read
@endcode
@todo need additional functions to aid ISRs in retrieving status
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/spi.h>
#include <libopencm3/stm32/rcc.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief Configure the SPI as Master.
The SPI peripheral is configured as a master with communication parameters
baudrate, frame format lsb/msb first, clock polarity and phase. The SPI
enable, CRC enable, CRC next CRC length controls are not affected.
These must be controlled separately.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@param[in] br Unsigned int32. Baudrate @ref spi_baudrate.
@param[in] cpol Unsigned int32. Clock polarity @ref spi_cpol.
@param[in] cpha Unsigned int32. Clock Phase @ref spi_cpha.
@param[in] lsbfirst Unsigned int32. Frame format lsb/msb first @ref
spi_lsbfirst.
@returns int. Error code.
*/
int spi_init_master(uint32_t spi, uint32_t br, uint32_t cpol, uint32_t cpha,
uint32_t lsbfirst)
{
uint32_t reg32 = SPI_CR1(spi);
/* Reset all bits omitting SPE, CRCEN, CRCNEXT and CRCL bits. */
reg32 &= SPI_CR1_SPE | SPI_CR1_CRCEN | SPI_CR1_CRCNEXT | SPI_CR1_CRCL;
reg32 |= SPI_CR1_MSTR; /* Configure SPI as master. */
reg32 |= br; /* Set baud rate bits. */
reg32 |= cpol; /* Set CPOL value. */
reg32 |= cpha; /* Set CPHA value. */
reg32 |= lsbfirst; /* Set frame format (LSB- or MSB-first). */
SPI_CR2(spi) |= SPI_CR2_SSOE; /* common case */
SPI_CR1(spi) = reg32;
return 0; /* TODO */
}
void spi_send8(uint32_t spi, uint8_t data)
{
/* Wait for transfer finished. */
while (!(SPI_SR(spi) & SPI_SR_TXE));
SPI_DR8(spi) = data;
}
uint8_t spi_read8(uint32_t spi)
{
/* Wait for transfer finished. */
while (!(SPI_SR(spi) & SPI_SR_RXNE));
return SPI_DR8(spi);
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set CRC length to 8 bits
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_crcl_8bit(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_CRCL;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set CRC length to 16 bits
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_crcl_16bit(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_CRCL;
}
/** @brief SPI Set data size
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@param[in] data_s Unsigned int16. data size @ref spi_ds.
*/
void spi_set_data_size(uint32_t spi, uint16_t data_s)
{
SPI_CR2(spi) = (SPI_CR2(spi) & ~SPI_CR2_DS_MASK) |
(data_s & SPI_CR2_DS_MASK);
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set reception threshold to 8 bits
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_fifo_reception_threshold_8bit(uint32_t spi)
{
SPI_CR2(spi) |= SPI_CR2_FRXTH;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set reception threshold to 16 bits
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_fifo_reception_threshold_16bit(uint32_t spi)
{
SPI_CR2(spi) &= ~SPI_CR2_FRXTH;
}
/**@}*/

View File

@@ -0,0 +1,297 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
* Copyright (C) 2015 Robin Kreis <r.kreis@uni-bremen.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/common.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/tools.h>
#include <libopencm3/stm32/st_usbfs.h>
#include <libopencm3/usb/usbd.h>
#include "../../usb/usb_private.h"
#include "st_usbfs_core.h"
/* TODO - can't these be inside the impls, not globals from the core? */
uint8_t st_usbfs_force_nak[8];
struct _usbd_device st_usbfs_dev;
void st_usbfs_set_address(usbd_device *dev, uint8_t addr)
{
(void)dev;
/* Set device address and enable. */
SET_REG(USB_DADDR_REG, (addr & USB_DADDR_ADDR) | USB_DADDR_EF);
}
/**
* Set the receive buffer size for a given USB endpoint.
*
* @param dev the usb device handle returned from @ref usbd_init
* @param ep Index of endpoint to configure.
* @param size Size in bytes of the RX buffer. Legal sizes : {2,4,6...62}; {64,96,128...992}.
* @returns (uint16) Actual size set
*/
uint16_t st_usbfs_set_ep_rx_bufsize(usbd_device *dev, uint8_t ep, uint32_t size)
{
uint16_t realsize;
(void)dev;
/*
* Writes USB_COUNTn_RX reg fields : bits <14:10> are NUM_BLOCK; bit 15 is BL_SIZE
* - When (size <= 62), BL_SIZE is set to 0 and NUM_BLOCK set to (size / 2).
* - When (size > 62), BL_SIZE is set to 1 and NUM_BLOCK=((size / 32) - 1).
*
* This algo rounds to the next largest legal buffer size, except 0. Examples:
* size => BL_SIZE, NUM_BLOCK => Actual bufsize
* 0 0 0 ??? "Not allowed" according to RM0091, RM0008
* 1 0 1 2
* 61 0 31 62
* 63 1 1 64
*/
if (size > 62) {
/* Round up, div by 32 and sub 1 == (size + 31)/32 - 1 == (size-1)/32)*/
size = ((size - 1) >> 5) & 0x1F;
realsize = (size + 1) << 5;
/* Set BL_SIZE bit (no macro for this) */
size |= (1<<5);
} else {
/* round up and div by 2 */
size = (size + 1) >> 1;
realsize = size << 1;
}
/* write to the BL_SIZE and NUM_BLOCK fields */
USB_SET_EP_RX_COUNT(ep, size << 10);
return realsize;
}
void st_usbfs_ep_setup(usbd_device *dev, uint8_t addr, uint8_t type,
uint16_t max_size,
void (*callback) (usbd_device *usbd_dev,
uint8_t ep))
{
/* Translate USB standard type codes to STM32. */
const uint16_t typelookup[] = {
[USB_ENDPOINT_ATTR_CONTROL] = USB_EP_TYPE_CONTROL,
[USB_ENDPOINT_ATTR_ISOCHRONOUS] = USB_EP_TYPE_ISO,
[USB_ENDPOINT_ATTR_BULK] = USB_EP_TYPE_BULK,
[USB_ENDPOINT_ATTR_INTERRUPT] = USB_EP_TYPE_INTERRUPT,
};
uint8_t dir = addr & 0x80;
addr &= 0x7f;
/* Assign address. */
USB_SET_EP_ADDR(addr, addr);
USB_SET_EP_TYPE(addr, typelookup[type]);
if (dir || (addr == 0)) {
USB_SET_EP_TX_ADDR(addr, dev->pm_top);
if (callback) {
dev->user_callback_ctr[addr][USB_TRANSACTION_IN] =
(void *)callback;
}
USB_CLR_EP_TX_DTOG(addr);
USB_SET_EP_TX_STAT(addr, USB_EP_TX_STAT_NAK);
dev->pm_top += max_size;
}
if (!dir) {
uint16_t realsize;
USB_SET_EP_RX_ADDR(addr, dev->pm_top);
realsize = st_usbfs_set_ep_rx_bufsize(dev, addr, max_size);
if (callback) {
dev->user_callback_ctr[addr][USB_TRANSACTION_OUT] =
(void *)callback;
}
USB_CLR_EP_RX_DTOG(addr);
USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID);
dev->pm_top += realsize;
}
}
void st_usbfs_endpoints_reset(usbd_device *dev)
{
int i;
/* Reset all endpoints. */
for (i = 1; i < 8; i++) {
USB_SET_EP_TX_STAT(i, USB_EP_TX_STAT_DISABLED);
USB_SET_EP_RX_STAT(i, USB_EP_RX_STAT_DISABLED);
}
dev->pm_top = USBD_PM_TOP + (2 * dev->desc->bMaxPacketSize0);
}
void st_usbfs_ep_stall_set(usbd_device *dev, uint8_t addr,
uint8_t stall)
{
(void)dev;
if (addr == 0) {
USB_SET_EP_TX_STAT(addr, stall ? USB_EP_TX_STAT_STALL :
USB_EP_TX_STAT_NAK);
}
if (addr & 0x80) {
addr &= 0x7F;
USB_SET_EP_TX_STAT(addr, stall ? USB_EP_TX_STAT_STALL :
USB_EP_TX_STAT_NAK);
/* Reset to DATA0 if clearing stall condition. */
if (!stall) {
USB_CLR_EP_TX_DTOG(addr);
}
} else {
/* Reset to DATA0 if clearing stall condition. */
if (!stall) {
USB_CLR_EP_RX_DTOG(addr);
}
USB_SET_EP_RX_STAT(addr, stall ? USB_EP_RX_STAT_STALL :
USB_EP_RX_STAT_VALID);
}
}
uint8_t st_usbfs_ep_stall_get(usbd_device *dev, uint8_t addr)
{
(void)dev;
if (addr & 0x80) {
if ((*USB_EP_REG(addr & 0x7F) & USB_EP_TX_STAT) ==
USB_EP_TX_STAT_STALL) {
return 1;
}
} else {
if ((*USB_EP_REG(addr) & USB_EP_RX_STAT) ==
USB_EP_RX_STAT_STALL) {
return 1;
}
}
return 0;
}
void st_usbfs_ep_nak_set(usbd_device *dev, uint8_t addr, uint8_t nak)
{
(void)dev;
/* It does not make sense to force NAK on IN endpoints. */
if (addr & 0x80) {
return;
}
st_usbfs_force_nak[addr] = nak;
if (nak) {
USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_NAK);
} else {
USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID);
}
}
uint16_t st_usbfs_ep_write_packet(usbd_device *dev, uint8_t addr,
const void *buf, uint16_t len)
{
(void)dev;
addr &= 0x7F;
if ((*USB_EP_REG(addr) & USB_EP_TX_STAT) == USB_EP_TX_STAT_VALID) {
return 0;
}
st_usbfs_copy_to_pm(USB_GET_EP_TX_BUFF(addr), buf, len);
USB_SET_EP_TX_COUNT(addr, len);
USB_SET_EP_TX_STAT(addr, USB_EP_TX_STAT_VALID);
return len;
}
uint16_t st_usbfs_ep_read_packet(usbd_device *dev, uint8_t addr,
void *buf, uint16_t len)
{
(void)dev;
if ((*USB_EP_REG(addr) & USB_EP_RX_STAT) == USB_EP_RX_STAT_VALID) {
return 0;
}
len = MIN(USB_GET_EP_RX_COUNT(addr) & 0x3ff, len);
st_usbfs_copy_from_pm(buf, USB_GET_EP_RX_BUFF(addr), len);
USB_CLR_EP_RX_CTR(addr);
if (!st_usbfs_force_nak[addr]) {
USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID);
}
return len;
}
void st_usbfs_poll(usbd_device *dev)
{
uint16_t istr = *USB_ISTR_REG;
if (istr & USB_ISTR_RESET) {
USB_CLR_ISTR_RESET();
dev->pm_top = USBD_PM_TOP;
_usbd_reset(dev);
return;
}
if (istr & USB_ISTR_CTR) {
uint8_t ep = istr & USB_ISTR_EP_ID;
uint8_t type;
if (istr & USB_ISTR_DIR) {
/* OUT or SETUP? */
if (*USB_EP_REG(ep) & USB_EP_SETUP) {
type = USB_TRANSACTION_SETUP;
st_usbfs_ep_read_packet(dev, ep, &dev->control_state.req, 8);
} else {
type = USB_TRANSACTION_OUT;
}
} else {
type = USB_TRANSACTION_IN;
USB_CLR_EP_TX_CTR(ep);
}
if (dev->user_callback_ctr[ep][type]) {
dev->user_callback_ctr[ep][type] (dev, ep);
} else {
USB_CLR_EP_RX_CTR(ep);
}
}
if (istr & USB_ISTR_SUSP) {
USB_CLR_ISTR_SUSP();
if (dev->user_callback_suspend) {
dev->user_callback_suspend();
}
}
if (istr & USB_ISTR_WKUP) {
USB_CLR_ISTR_WKUP();
if (dev->user_callback_resume) {
dev->user_callback_resume();
}
}
if (istr & USB_ISTR_SOF) {
USB_CLR_ISTR_SOF();
if (dev->user_callback_sof) {
dev->user_callback_sof();
}
}
if (dev->user_callback_sof) {
*USB_CNTR_REG |= USB_CNTR_SOFM;
} else {
*USB_CNTR_REG &= ~USB_CNTR_SOFM;
}
}

View File

@@ -0,0 +1,76 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
* Copyright (C) 2015 Robin Kreis <r.kreis@uni-bremen.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/>.
*/
/*
* This is a "private" header file for usbd implementations.
* As opposed to the "public" headers under include that describe the hardware,
* this is purely an implementation detail of usbd drivers.
*/
#ifndef ST_USBFS_CORE
#define ST_USBFS_CORE
#include <libopencm3/stm32/st_usbfs.h>
#include <libopencm3/usb/usbd.h>
#define USBD_PM_TOP 0x40
void st_usbfs_set_address(usbd_device *dev, uint8_t addr);
uint16_t st_usbfs_set_ep_rx_bufsize(usbd_device *dev, uint8_t ep, uint32_t size);
void st_usbfs_ep_setup(usbd_device *usbd_dev, uint8_t addr,
uint8_t type, uint16_t max_size,
void (*callback) (usbd_device *usbd_dev,
uint8_t ep));
void st_usbfs_endpoints_reset(usbd_device *usbd_dev);
void st_usbfs_ep_stall_set(usbd_device *usbd_dev, uint8_t addr, uint8_t stall);
uint8_t st_usbfs_ep_stall_get(usbd_device *usbd_dev, uint8_t addr);
void st_usbfs_ep_nak_set(usbd_device *usbd_dev, uint8_t addr, uint8_t nak);
uint16_t st_usbfs_ep_write_packet(usbd_device *usbd_dev, uint8_t addr,
const void *buf, uint16_t len);
uint16_t st_usbfs_ep_read_packet(usbd_device *usbd_dev, uint8_t addr,
void *buf, uint16_t len);
void st_usbfs_poll(usbd_device *usbd_dev);
/* These must be implemented by the device specific driver */
/**
* Copy a data buffer to packet memory.
*
* @param vPM Destination pointer into packet memory.
* @param buf Source pointer to data buffer.
* @param len Number of bytes to copy.
*/
void st_usbfs_copy_from_pm(void *buf, const volatile void *vPM, uint16_t len);
/**
* Copy a data buffer from packet memory.
*
* @param vPM Destination pointer into packet memory.
* @param buf Source pointer to data buffer.
* @param len Number of bytes to copy.
*/
void st_usbfs_copy_to_pm(volatile void *vPM, const void *buf, uint16_t len);
extern uint8_t st_usbfs_force_nak[8];
extern struct _usbd_device st_usbfs_dev;
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
/** @addtogroup timer_file
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Edward Cheeseman <evbuilder@users.sourceforge.org>
* Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/timer.h>
/*---------------------------------------------------------------------------*/
/** @brief Set Input Polarity
The timer channel must be set to input capture mode.
@param[in] timer_peripheral Unsigned int32. Timer register address base
@param[in] ic ::tim_ic_id. Input Capture channel designator.
@param[in] pol ::tim_ic_pol. Input Capture polarity control.
*/
void timer_ic_set_polarity(uint32_t timer_peripheral, enum tim_ic_id ic,
enum tim_ic_pol pol)
{
/* Clear CCxP and CCxNP to zero. For both edge trigger both fields are
* set. Case 10 is invalid.
*/
TIM_CCER(timer_peripheral) &= ~(0xa << (ic * 4));
switch (pol) {
case TIM_IC_RISING: /* 00 */
break;
case TIM_IC_BOTH: /* 11 */
TIM_CCER(timer_peripheral) |= (0xa << (ic * 4));
break;
case TIM_IC_FALLING: /* 01 */
TIM_CCER(timer_peripheral) |= (0x2 << (ic * 4));
}
}
/**@}*/

View File

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

View File

@@ -0,0 +1,427 @@
/** @addtogroup usart_file USART peripheral API
@ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
This library supports the USART/UART in the STM32F series
of ARM Cortex Microcontrollers by ST Microelectronics.
Devices can have up to 3 USARTs and 2 UARTs.
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/usart.h>
#include <libopencm3/stm32/rcc.h>
/*---------------------------------------------------------------------------*/
/** @brief USART Set Baudrate.
The baud rate is computed from the APB high-speed prescaler clock (for
USART1/6) or the APB low-speed prescaler clock (for other USARTs). These values
must be correctly set before calling this function (refer to the
rcc_clock_setup-* functions in RCC).
Note: For LPUART, baudrates over 2**24 (~16.7 Mbaud) may overflow
the calculation and are therefore not supported by this function.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] baud unsigned 32 bit. Baud rate specified in Hz.
*/
void usart_set_baudrate(uint32_t usart, uint32_t baud)
{
uint32_t clock = rcc_apb1_frequency;
#if defined USART1
if ((usart == USART1)
#if defined USART6
|| (usart == USART6)
#endif
) {
clock = rcc_apb2_frequency;
}
#endif
/*
* Yes it is as simple as that. The reference manual is
* talking about fractional calculation but it seems to be only
* marketing babble to sound awesome. It is nothing else but a
* simple divider to generate the correct baudrate.
*
* Note: We round() the value rather than floor()ing it, for more
* accurate divisor selection.
*/
#ifdef LPUART1
if (usart == LPUART1) {
USART_BRR(usart) = (clock / baud) * 256
+ ((clock % baud) * 256 + baud / 2) / baud;
return;
}
#endif
USART_BRR(usart) = (clock + baud / 2) / baud;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Set Word Length.
The word length is set to 8 or 9 bits. Note that the last bit will be a parity
bit if parity is enabled, in which case the data length will be 7 or 8 bits
respectively.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] bits unsigned 32 bit. Word length in bits 8 or 9.
*/
void usart_set_databits(uint32_t usart, uint32_t bits)
{
if (bits == 8) {
USART_CR1(usart) &= ~USART_CR1_M; /* 8 data bits */
} else {
USART_CR1(usart) |= USART_CR1_M; /* 9 data bits */
}
}
/*---------------------------------------------------------------------------*/
/** @brief USART Set Stop Bit(s).
The stop bits are specified as 0.5, 1, 1.5 or 2.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] stopbits unsigned 32 bit. Stop bits @ref usart_cr2_stopbits.
*/
void usart_set_stopbits(uint32_t usart, uint32_t stopbits)
{
uint32_t reg32;
reg32 = USART_CR2(usart);
reg32 = (reg32 & ~USART_CR2_STOPBITS_MASK) | stopbits;
USART_CR2(usart) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Set Parity.
The parity bit can be selected as none, even or odd.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] parity unsigned 32 bit. Parity @ref usart_cr1_parity.
*/
void usart_set_parity(uint32_t usart, uint32_t parity)
{
uint32_t reg32;
reg32 = USART_CR1(usart);
reg32 = (reg32 & ~USART_PARITY_MASK) | parity;
USART_CR1(usart) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Set Rx/Tx Mode.
The mode can be selected as Rx only, Tx only or Rx+Tx.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] mode unsigned 32 bit. Mode @ref usart_cr1_mode.
*/
void usart_set_mode(uint32_t usart, uint32_t mode)
{
uint32_t reg32;
reg32 = USART_CR1(usart);
reg32 = (reg32 & ~USART_MODE_MASK) | mode;
USART_CR1(usart) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Set Hardware Flow Control.
The flow control bit can be selected as none, RTS, CTS or RTS+CTS.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] flowcontrol unsigned 32 bit. Flowcontrol @ref usart_cr3_flowcontrol.
*/
void usart_set_flow_control(uint32_t usart, uint32_t flowcontrol)
{
uint32_t reg32;
reg32 = USART_CR3(usart);
reg32 = (reg32 & ~USART_FLOWCONTROL_MASK) | flowcontrol;
USART_CR3(usart) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Enable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_enable(uint32_t usart)
{
USART_CR1(usart) |= USART_CR1_UE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Disable.
At the end of the current frame, the USART is disabled to reduce power.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_disable(uint32_t usart)
{
USART_CR1(usart) &= ~USART_CR1_UE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Send Data Word with Blocking
Blocks until the transmit data buffer becomes empty then writes the next data
word for transmission.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] data unsigned 16 bit.
*/
void usart_send_blocking(uint32_t usart, uint16_t data)
{
usart_wait_send_ready(usart);
usart_send(usart, data);
}
/*---------------------------------------------------------------------------*/
/** @brief USART Read a Received Data Word with Blocking.
Wait until a data word has been received then return the word.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@returns unsigned 16 bit data word.
*/
uint16_t usart_recv_blocking(uint32_t usart)
{
usart_wait_recv_ready(usart);
return usart_recv(usart);
}
/*---------------------------------------------------------------------------*/
/** @brief USART Receiver DMA Enable.
DMA is available on:
@li USART1 Rx DMA1 channel 5.
@li USART2 Rx DMA1 channel 6.
@li USART3 Rx DMA1 channel 3.
@li UART4 Rx DMA2 channel 3.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_enable_rx_dma(uint32_t usart)
{
USART_CR3(usart) |= USART_CR3_DMAR;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Receiver DMA Disable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_disable_rx_dma(uint32_t usart)
{
USART_CR3(usart) &= ~USART_CR3_DMAR;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Transmitter DMA Enable.
DMA is available on:
@li USART1 Tx DMA1 channel 4.
@li USART2 Tx DMA1 channel 7.
@li USART3 Tx DMA1 channel 2.
@li UART4 Tx DMA2 channel 5.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_enable_tx_dma(uint32_t usart)
{
USART_CR3(usart) |= USART_CR3_DMAT;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Transmitter DMA Disable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_disable_tx_dma(uint32_t usart)
{
USART_CR3(usart) &= ~USART_CR3_DMAT;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Receiver Interrupt Enable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_enable_rx_interrupt(uint32_t usart)
{
USART_CR1(usart) |= USART_CR1_RXNEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Receiver Interrupt Disable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_disable_rx_interrupt(uint32_t usart)
{
USART_CR1(usart) &= ~USART_CR1_RXNEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Transmitter Interrupt Enable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_enable_tx_interrupt(uint32_t usart)
{
USART_CR1(usart) |= USART_CR1_TXEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Transmitter Interrupt Disable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_disable_tx_interrupt(uint32_t usart)
{
USART_CR1(usart) &= ~USART_CR1_TXEIE;
}
/*---------------------------------------------------------------------------*/
/**
* @brief USART Transmission Complete Interrupt Enable
*
* @param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_enable_tx_complete_interrupt(uint32_t usart)
{
USART_CR1(usart) |= USART_CR1_TCIE;
}
/*---------------------------------------------------------------------------*/
/**
* @brief USART Transmission Complete Interrupt Disable
*
* @param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_disable_tx_complete_interrupt(uint32_t usart)
{
USART_CR1(usart) &= ~USART_CR1_TCIE;
}
/** @brief USART Idle Interrupt Enable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_enable_idle_interrupt(uint32_t usart)
{
USART_CR1(usart) |= USART_CR1_IDLEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Idle Interrupt Disable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_disable_idle_interrupt(uint32_t usart)
{
USART_CR1(usart) &= ~USART_CR1_IDLEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Error Interrupt Enable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_enable_error_interrupt(uint32_t usart)
{
USART_CR3(usart) |= USART_CR3_EIE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Error Interrupt Disable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_disable_error_interrupt(uint32_t usart)
{
USART_CR3(usart) &= ~USART_CR3_EIE;
}
/**@}*/

View File

@@ -0,0 +1,114 @@
/** @addtogroup usart_file
@ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
This library supports the USART/UART in the STM32F series
of ARM Cortex Microcontrollers by ST Microelectronics.
Devices can have up to 3 USARTs and 2 UARTs.
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/usart.h>
#include <libopencm3/stm32/rcc.h>
/*---------------------------------------------------------------------------*/
/** @brief USART Send a Data Word.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] data unsigned 16 bit.
*/
void usart_send(uint32_t usart, uint16_t data)
{
/* Send data. */
USART_DR(usart) = (data & USART_DR_MASK);
}
/*---------------------------------------------------------------------------*/
/** @brief USART Read a Received Data Word.
If parity is enabled the MSB (bit 7 or 8 depending on the word length) is the
parity bit.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@returns unsigned 16 bit data word.
*/
uint16_t usart_recv(uint32_t usart)
{
/* Receive data. */
return USART_DR(usart) & USART_DR_MASK;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Wait for Transmit Data Buffer Empty
Blocks until the transmit data buffer becomes empty and is ready to accept the
next data word.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_wait_send_ready(uint32_t usart)
{
/* Wait until the data has been transferred into the shift register. */
while ((USART_SR(usart) & USART_SR_TXE) == 0);
}
/*---------------------------------------------------------------------------*/
/** @brief USART Wait for Received Data Available
Blocks until the receive data buffer holds a valid received data word.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_wait_recv_ready(uint32_t usart)
{
/* Wait until the data is ready to be received. */
while ((USART_SR(usart) & USART_SR_RXNE) == 0);
}
/*---------------------------------------------------------------------------*/
/** @brief USART Read a Status Flag.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags.
@returns boolean: flag set.
*/
bool usart_get_flag(uint32_t usart, uint32_t flag)
{
return ((USART_SR(usart) & flag) != 0);
}
/**@}*/

View File

@@ -0,0 +1,72 @@
/*
* 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/usart.h>
void usart_enable_fifos(uint32_t usart) {
USART_CR1(usart) |= USART_CR1_FIFOEN;
}
void usart_disable_fifos(uint32_t usart) {
USART_CR1(usart) &= ~USART_CR1_FIFOEN;
}
void usart_enable_tx_fifo_empty_interrupt(uint32_t usart) {
USART_CR1(usart) |= USART_CR1_TXFEIE;
}
void usart_disable_tx_fifo_empty_interrupt(uint32_t usart) {
USART_CR1(usart) &= ~USART_CR1_TXFEIE;
}
void usart_enable_tx_fifo_threshold_interrupt(uint32_t usart) {
USART_CR3(usart) |= USART_CR3_TXFTIE;
}
void usart_disable_tx_fifo_threshold_interrupt(uint32_t usart) {
USART_CR3(usart) &= ~USART_CR3_TXFTIE;
}
void usart_set_tx_fifo_threshold(uint32_t usart,
usart_fifo_threshold_t threshold) {
uint32_t cr3 = USART_CR3(usart) &
~(USART_FIFO_THRESH_MASK << USART_CR3_TXFTCFG_SHIFT);
USART_CR3(usart) = cr3 | (threshold << USART_CR3_TXFTCFG_SHIFT);
}
void usart_enable_rx_fifo_full_interrupt(uint32_t usart) {
USART_CR1(usart) |= USART_CR1_RXFFIE;
}
void usart_disable_rx_fifo_full_interrupt(uint32_t usart) {
USART_CR1(usart) &= ~USART_CR1_RXFFIE;
}
void usart_enable_rx_fifo_threshold_interrupt(uint32_t usart) {
USART_CR3(usart) |= USART_CR3_RXFTIE;
}
void usart_disable_rx_fifo_threshold_interrupt(uint32_t usart) {
USART_CR3(usart) &= ~USART_CR3_RXFTIE;
}
void usart_set_rx_fifo_threshold(uint32_t usart,
usart_fifo_threshold_t threshold) {
uint32_t cr3 = USART_CR3(usart) &
~(USART_FIFO_THRESH_MASK << USART_CR3_RXFTCFG_SHIFT);
USART_CR3(usart) = cr3 | (threshold << USART_CR3_RXFTCFG_SHIFT);
}

View File

@@ -0,0 +1,306 @@
/** @addtogroup usart_file
@ingroup peripheral_apis
@author @htmlonly &copy; @endhtmlonly 2016 Cem Basoglu <cem.basoglu@web.de>
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2016 Cem Basoglu <cem.basoglu@web.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/usart.h>
/*---------------------------------------------------------------------------*/
/** @brief USART enable data inversion
Logical data from the data register are send/received in negative/inverse
logic. (1=L, 0=H). The parity bit is also inverted.
@note This bit field can only be written when the USART is disabled.
@param[in] usart USART block register address base @ref usart_reg_base
*/
void usart_enable_data_inversion(uint32_t usart)
{
USART_CR2(usart) |= USART_CR2_DATAINV;
}
/*---------------------------------------------------------------------------*/
/** @brief USART disable data inversion
Logical data from the data register are send/received in positive/direct logic.
(1=H, 0=L)
@note This bit field can only be written when the USART is disabled.
@param[in] usart USART block register address base @ref usart_reg_base
*/
void usart_disable_data_inversion(uint32_t usart)
{
USART_CR2(usart) &= ~USART_CR2_DATAINV;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Enable TX pin active level inversion
TX pin signal values are inverted. (VDD =0/mark, Gnd=1/idle).
@note This bit field can only be written when the USART is disabled.
@param[in] usart USART block register address base @ref usart_reg_base
*/
void usart_enable_tx_inversion(uint32_t usart)
{
USART_CR2(usart) |= USART_CR2_TXINV;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Disable TX pin active level inversion
TX pin signal works using the standard logic levels (VDD =1/idle, Gnd=0/mark)
@note This bit field can only be written when the USART is disabled.
@param[in] usart USART block register address base @ref usart_reg_base
*/
void usart_disable_tx_inversion(uint32_t usart)
{
USART_CR2(usart) &= ~USART_CR2_TXINV;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Enable RX pin active level inversion
RX pin signal values are inverted. (VDD =0/mark, Gnd=1/idle).
This bit field can only be written when the USART is disabled.
@param[in] usart USART block register address base @ref usart_reg_base
*/
void usart_enable_rx_inversion(uint32_t usart)
{
USART_CR2(usart) |= USART_CR2_RXINV;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Disable RX pin active level inversion
RX pin signal works using the standard logic levels (VDD =1/idle, Gnd=0/mark)
This bit field can only be written when the USART is disabled.
@param[in] usart USART block register address base @ref usart_reg_base
*/
void usart_disable_rx_inversion(uint32_t usart)
{
USART_CR2(usart) &= ~USART_CR2_RXINV;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Enable Half-duplex
- The TX and RX lines are internally connected.
- The RX pin is no longer used
- The TX pin is always released when no data is transmitted. Thus,
it acts as a standard I/O in idle or in reception. It means
that the I/O must be configured so that TX is configured as
alternate function open-drain with an external pull-up.
Apart from this, the communication protocol is similar to normal USART mode.
Any conflicts on the line must be managed by software
This bit field can only be written when the USART is disabled.
@param[in] usart USART block register address base @ref usart_reg_base
*/
void usart_enable_halfduplex(uint32_t usart)
{
USART_CR3(usart) |= USART_CR3_HDSEL;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Disable Half-duplex
This bit field can only be written when the USART is disabled.
@param[in] usart USART block register address base @ref usart_reg_base
*/
void usart_disable_halfduplex(uint32_t usart)
{
USART_CR3(usart) &= ~USART_CR3_HDSEL;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Set receiver timeout value
Sets the receive timeout value in terms of number of bit duration.
The @ref USART_ISR_RTOF is set if, after the last received character,
no new start bit is detected for more than the receive timeout value.
@note The timeout value can also be written when USART is enabled.
If the new value is lower/equals the internal hardware counter,
the RTOF flag will be set.
@param[in] usart USART block register address base @ref usart_reg_base
@param[in] value The receive timeout value in terms of number of bit duration.
*/
void usart_set_rx_timeout_value(uint32_t usart, uint32_t value)
{
uint32_t reg;
reg = USART_RTOR(usart) & ~USART_RTOR_RTO_MASK;
reg |= (USART_RTOR_RTO_VAL(value) & USART_RTOR_RTO_MASK);
USART_RTOR(usart) = reg;
}
/*---------------------------------------------------------------------------*/
/** @brief USART enable receive timeout function
@note If the USART does not support the Receiver timeout feature,
this bit is reserved and forced by hardware to 0.
@param[in] usart USART block register address base @ref usart_reg_base
*/
void usart_enable_rx_timeout(uint32_t usart)
{
USART_CR2(usart) |= USART_CR2_RTOEN;
}
/*---------------------------------------------------------------------------*/
/** @brief USART disable receive timeout function
@note If the USART does not support the Receiver timeout feature,
this bit is reserved and forced by hardware to 0.
@param[in] usart USART block register address base @ref usart_reg_base
*/
void usart_disable_rx_timeout(uint32_t usart)
{
USART_CR2(usart) &= ~USART_CR2_RTOEN;
}
/*---------------------------------------------------------------------------*/
/** @brief USART enable receive timeout interrupt
An interrupt is generated when the RTOF Flag is set
in the @ref USART_ISR register.
@note If the USART does not support the Receiver timeout feature,
this bit is reserved and forced by hardware to 0.
@param[in] usart USART block register address base @ref usart_reg_base
*/
void usart_enable_rx_timeout_interrupt(uint32_t usart)
{
USART_CR1(usart) |= USART_CR1_RTOIE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART disable receive timeout interrupt
@note If the USART does not support the Receiver timeout feature,
this bit is reserved and forced by hardware to 0.
@param[in] usart USART block register address base @ref usart_reg_base
*/
void usart_disable_rx_timeout_interrupt(uint32_t usart)
{
USART_CR1(usart) &= ~USART_CR1_RTOIE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Send a Data Word.
*
* @param[in] usart unsigned 32 bit. USART block register address base @ref
* usart_reg_base
* @param[in] data unsigned 16 bit.
*/
void usart_send(uint32_t usart, uint16_t data)
{
/* Send data. */
USART_TDR(usart) = (data & USART_TDR_MASK);
}
/*---------------------------------------------------------------------------*/
/** @brief USART Read a Received Data Word.
*
* If parity is enabled the MSB (bit 7 or 8 depending on the word length) is
* the parity bit.
*
* @param[in] usart unsigned 32 bit. USART block register address base @ref
* usart_reg_base
* @returns unsigned 16 bit data word.
*/
uint16_t usart_recv(uint32_t usart)
{
/* Receive data. */
return USART_RDR(usart) & USART_RDR_MASK;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Wait for Transmit Data Buffer Empty
*
* Blocks until the transmit data buffer becomes empty and is ready to accept
* the next data word.
*
* @param[in] usart unsigned 32 bit. USART block register address base @ref
* usart_reg_base
*/
void usart_wait_send_ready(uint32_t usart)
{
/* Wait until the data has been transferred into the shift register. */
while ((USART_ISR(usart) & USART_ISR_TXE) == 0);
}
/*---------------------------------------------------------------------------*/
/** @brief USART Wait for Received Data Available
*
* Blocks until the receive data buffer holds a valid received data word.
*
* @param[in] usart unsigned 32 bit. USART block register address base @ref
* usart_reg_base
*/
void usart_wait_recv_ready(uint32_t usart)
{
/* Wait until the data is ready to be received. */
while ((USART_ISR(usart) & USART_ISR_RXNE) == 0);
}
/*---------------------------------------------------------------------------*/
/** @brief USART Read a Status Flag.
*
* @param[in] usart unsigned 32 bit. USART block register address base @ref
* usart_reg_base
* @param[in] flag Unsigned int32. Status register flag @ref usart_isr_values.
* @returns boolean: flag set.
*/
bool usart_get_flag(uint32_t usart, uint32_t flag)
{
return ((USART_ISR(usart) & flag) != 0);
}
/**@}*/

View File

@@ -0,0 +1,65 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2013 Frantisek Burian <BuFran@seznam.cz>
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
LIBNAME = libopencm3_stm32f0
SRCLIBDIR ?= ../..
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-Wall -Wextra -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../../include -fno-common \
-mcpu=cortex-m0 $(FP_FLAGS) -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DSTM32F0
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
ARFLAGS = rcs
OBJS += adc.o adc_common_v2.o
OBJS += can.o
OBJS += comparator.o
OBJS += crc_common_all.o crc_v2.o
OBJS += crs_common_all.o
OBJS += dac_common_all.o dac_common_v1.o
OBJS += desig_common_all.o desig_common_v1.o
OBJS += dma_common_l1f013.o dma_common_csel.o
OBJS += exti_common_all.o
OBJS += flash.o flash_common_all.o flash_common_f.o flash_common_f01.o
OBJS += gpio_common_all.o gpio_common_f0234.o
OBJS += iwdg_common_all.o
OBJS += i2c_common_v2.o
OBJS += pwr_common_v1.o
OBJS += rcc.o rcc_common_all.o
OBJS += rtc_common_l1f024.o
OBJS += spi_common_all.o spi_common_v2.o
OBJS += timer_common_all.o timer_common_f0234.o
OBJS += usart_common_all.o usart_common_v2.o
OBJS += usb.o usb_control.o usb_standard.o usb_msc.o
OBJS += usb_hid.o
OBJS += usb_audio.o usb_cdc.o usb_midi.o
OBJS += st_usbfs_core.o st_usbfs_v2.o
VPATH += ../../usb:../:../../cm3:../common
include ../../Makefile.include

View File

@@ -0,0 +1,540 @@
/** @addtogroup adc_file ADC peripheral API
* @ingroup peripheral_apis
*
* based on F3 file
*
* @date 14 July 2013
*
* 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/cm3/assert.h>
#include <libopencm3/stm32/adc.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/**
* @defgroup adc_api_opmode ADC Operation mode API
* @ingroup adc_file
*
* @brief ADC Result API
*
*@{*/
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Discontinuous Mode for Regular Conversions
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_enable_discontinuous_mode(uint32_t adc)
{
ADC_CFGR1(adc) |= ADC_CFGR1_DISCEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Discontinuous Mode for Regular Conversions
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_discontinuous_mode(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_DISCEN;
}
/*---------------------------------------------------------------------------*/
/** ADC Set operation mode
*
* There are some operation modes, common for entire stm32 branch. In the text
* the braces are describing result to single trigger event. The trigger event
* is described by character T in the description. The ADC is configured to
* convert list of inputs [0, 1, 2, 3]. In Grouped modes, there is used group
* size of 2 conversions in the examples
*
* @li @c ADC_MODE_SEQUENTIAL: T(0) T(1) T(2) T(3)[EOSEQ] T(0) T(1) T(2) ...
*
* In this mode, after the trigger event a single channel is converted and the
* next channel in the list is prepared to convert on next trigger edge.
*
* @note This mode can be emulated by ADC_MODE_GROUPED with group size
* of 1.
*
* @li @c ADC_MODE_SCAN: T(0123)[EOSEQ] T(0123)[EOSEQ] T(0123)[EOSEQ]
*
* In this mode, after the trigger event, all channels will be converted once,
* storing results sequentially.
*
* @note The DMA must be configured properly for more than single channel to
* convert.
*
* @li @c ADC_MODE_SCAN_INFINITE: T(0123[EOSEQ]0123[EOSEQ]0123[EOSEQ]...)
*
* In this mode, after the trigger event, all channels from the list are
* converted. At the end of list, the conversion continues from the beginning.
*
* @note The DMA must be configured properly to operate in this mode.@par
*
* @li @c ADC_MODE_GROUPED: T(12) T(34)[EOSEQ] T(12) T(34)[EOSEQ] T(12)
*
* In this mode, after the trigger event, a specified group size of channels
* are converted. If the end of channel list occurs, the EOSEQ is generated
* and on the next trigger it wraps to the beginning.
*
* @note The DMA must be configured properly to operate on more than single
* channel conversion groups.
*
* @warning not all families supports all modes of operation of ADC.
*
*/
/*---------------------------------------------------------------------------*/
/** @brief ADC Set conversion operation mode
*
* @note on SEQUENTIAL mode, the trigger event is necessary to start conversion.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] opmode ADC operation mode
*/
void adc_set_operation_mode(uint32_t adc, enum adc_opmode opmode)
{
switch (opmode) {
case ADC_MODE_SEQUENTIAL:
ADC_CFGR1(adc) &= ~ADC_CFGR1_CONT;
ADC_CFGR1(adc) |= ADC_CFGR1_DISCEN;
break;
case ADC_MODE_SCAN:
ADC_CFGR1(adc) &= ~(ADC_CFGR1_CONT | ADC_CFGR1_DISCEN);
break;
case ADC_MODE_SCAN_INFINITE:
ADC_CFGR1(adc) &= ~ADC_CFGR1_DISCEN;
ADC_CFGR1(adc) |= ADC_CFGR1_CONT;
break;
}
}
/**@}*/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/**
* @defgroup adc_api_trigger ADC Trigger API
* @ingroup adc_file
*
* @brief ADC Trigger API
*
*@{*/
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable an External Trigger for Regular Channels
*
* This enables an external trigger for set of defined regular channels, and
* sets the polarity of the trigger event: rising or falling edge or both. Note
* that if the trigger polarity is zero, triggering is disabled.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] trigger Unsigned int32. Trigger identifier
* @ref adc_trigger_regular
* @param[in] polarity Unsigned int32. Trigger polarity @ref
* adc_trigger_polarity_regular
*/
void adc_enable_external_trigger_regular(uint32_t adc, uint32_t trigger,
uint32_t polarity)
{
ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_EXTSEL) | trigger;
ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_EXTEN_MASK) | polarity;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable an External Trigger for Regular Channels
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_external_trigger_regular(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_EXTEN_MASK;
}
/**@}*/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/**
* @defgroup adc_api_interrupts ADC Interrupt configuration API
* @ingroup adc_file
*
* @brief ADC Interrupt configuration API
*
*@{*/
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog Interrupt
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_enable_watchdog_interrupt(uint32_t adc)
{
ADC_IER(adc) |= ADC_IER_AWD1IE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Regular End-Of-Conversion Interrupt
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_watchdog_interrupt(uint32_t adc)
{
ADC_IER(adc) &= ~ADC_IER_AWD1IE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read the Analog Watchdog Flag
*
* This flag is set when the converted voltage crosses the high or low
* thresholds.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @returns bool true, if the signal is out of defined analog range.
*/
bool adc_get_watchdog_flag(uint32_t adc)
{
return ADC_ISR(adc) & ADC_ISR_AWD1;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Clear Analog Watchdog Flag
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_clear_watchdog_flag(uint32_t adc)
{
ADC_ISR(adc) = ADC_ISR_AWD1;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Regular End-Of-Conversion Sequence Interrupt
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_enable_eoc_sequence_interrupt(uint32_t adc)
{
ADC_IER(adc) |= ADC_IER_EOSEQIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Regular End-Of-Conversion Sequence Interrupt
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_eoc_sequence_interrupt(uint32_t adc)
{
ADC_IER(adc) &= ~ADC_IER_EOSEQIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read the Regular End-Of-Conversion Sequence Flag
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
bool adc_get_eoc_sequence_flag(uint32_t adc)
{
return ADC_ISR(adc) & ADC_ISR_EOSEQ;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Clear Regular End-Of-Conversion Sequence Flag
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_clear_eoc_sequence_flag(uint32_t adc)
{
ADC_ISR(adc) = ADC_ISR_EOSEQ;
}
/**@}*/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/**
* @defgroup adc_api_config ADC Basic configuration API
* @ingroup adc_file
*
* @brief ADC Basic configuration API
*
*@{*/
/*---------------------------------------------------------------------------*/
/** @brief ADC Set Clock Source
*
* The ADC clock taken from the many sources.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] source Unsigned int32. Source (@ref adc_api_clksource)
*/
void adc_set_clk_source(uint32_t adc, uint32_t source)
{
ADC_CFGR2(adc) = ((ADC_CFGR2(adc) & ~ADC_CFGR2_CKMODE) | source);
}
/*---------------------------------------------------------------------------*/
/** @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 18 channels. If this is called during conversion, the
* current conversion is reset and conversion begins again with the newly
* defined group.
*
* @warning This core doesn't support the random order of ADC conversions.
* The channel list must be ordered by channel number.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] length Unsigned int8. Number of channels in the group.
* @param[in] channel Unsigned int8[]. Set of channels to convert, integers
* 0..18.
*/
void adc_set_regular_sequence(uint32_t adc, uint8_t length, uint8_t channel[])
{
uint32_t reg32 = 0;
uint8_t i = 0;
bool stepup = false, stepdn = false;
if (length == 0) {
ADC_CHSELR(adc) = 0;
return;
}
reg32 |= (1 << channel[0]);
for (i = 1; i < length; i++) {
reg32 |= (1 << channel[i]);
stepup |= channel[i-1] < channel[i];
stepdn |= channel[i-1] > channel[i];
}
/* Check, if the channel list is in order */
if (stepup && stepdn) {
cm3_assert_not_reached();
}
/* Update the scan direction flag */
if (stepdn) {
ADC_CFGR1(adc) |= ADC_CFGR1_SCANDIR;
} else {
ADC_CFGR1(adc) &= ~ADC_CFGR1_SCANDIR;
}
ADC_CHSELR(adc) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @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 base address (@ref adc_reg_base)
* @param[in] time Unsigned int8. Sampling time selection (@ref adc_api_smptime)
*/
void adc_set_sample_time_on_all_channels(uint32_t adc, uint8_t time)
{
ADC_SMPR(adc) = time & ADC_SMPR_SMP;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable The VBat Sensor
*
* This enables the battery voltage measurements on channel 17.
*/
void adc_enable_vbat_sensor(void)
{
ADC_CCR(ADC1) |= ADC_CCR_VBATEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable The VBat Sensor
*
* Disabling this will reduce power consumption from the battery voltage
* measurement.
*/
void adc_disable_vbat_sensor(void)
{
ADC_CCR(ADC1) &= ~ADC_CCR_VBATEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Start the calibration procedure
* @deprecated Replaced by adc_calibrate/_async/is_calibrating
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_calibrate_start(uint32_t adc)
{
ADC_CR(adc) = ADC_CR_ADCAL;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Wait to finish the ADC calibration procedure
* @deprecated Replaced by adc_calibrate/_async/is_calibrating
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_calibrate_wait_finish(uint32_t adc)
{
while (ADC_CR(adc) & ADC_CR_ADCAL);
}
/**@}*/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/**
* @defgroup adc_api_wdg ADC Analog watchdog API
* @ingroup adc_file
*
* @brief ADC analog watchdog API definitions.
*
* The analog watchdog allows the monitoring of an analog signal between two
* threshold levels. The thresholds must be preset. Analog watchdog is disabled
* by default.
*
* @warning Comparison is done before data alignment takes place, so the
* thresholds are left-aligned.
*
* Example 1: Enable watchdog checking on all channels
*
* @code
* // in configuration
* adc_enable_analog_watchdog_on_all_channels(ADC1);
* adc_set_watchdog_high_threshold(ADC1, 0xE00);
* adc_set_watchdog_low_threshold(ADC1, 0x200);
*
* // in the main application thread
* if (adc_get_watchdog_flag(ADC1)) {
* // the converted signal is out of AWD ranges
* adc_clear_watchdog_flag(ADC1);
* }
* @endcode
*
* Example 2: Enable watchdog checking on channel 5
*
* @code
* // in configuration
* adc_enable_analog_watchdog_on_selected_channel(ADC1,5);
* adc_set_watchdog_high_threshold(ADC1, 0xE00);
* adc_set_watchdog_low_threshold(ADC1, 0x200);
*
* // in the main application thread
* if (adc_get_watchdog_flag(ADC1)) {
* // the converted signal is out of AWD ranges
* adc_clear_watchdog_flag(ADC1);
* }
* @endcode
*@{*/
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog for All Channels
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_enable_analog_watchdog_on_all_channels(uint32_t adc)
{
ADC_CFGR1(adc) |= ADC_CFGR1_AWD1EN;
ADC_CFGR1(adc) &= ~ADC_CFGR1_AWD1SGL;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog for a Selected Channel
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] chan Unsigned int8. ADC channel number @ref adc_api_channel
*/
void adc_enable_analog_watchdog_on_selected_channel(uint32_t adc, uint8_t chan)
{
ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_AWD1CH) |
ADC_CFGR1_AWD1CH_VAL(chan);
ADC_CFGR1(adc) |= ADC_CFGR1_AWD1EN | ADC_CFGR1_AWD1SGL;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Analog Watchdog
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_analog_watchdog(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_AWD1EN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set Analog Watchdog Upper Threshold
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] threshold Upper threshold value
*/
void adc_set_watchdog_high_threshold(uint32_t adc, uint16_t threshold)
{
ADC_TR1(adc) = (ADC_TR1(adc) & ~ADC_TR1_HT) | ADC_TR1_HT_VAL(threshold);
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set Analog Watchdog Lower Threshold
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] threshold Lower threshold value
*/
void adc_set_watchdog_low_threshold(uint32_t adc, uint16_t threshold)
{
ADC_TR1(adc) = (ADC_TR1(adc) & ~ADC_TR1_LT) | ADC_TR1_LT_VAL(threshold);
}
/**@}*/
/*---------------------------------------------------------------------------*/
/**@}*/

View File

@@ -0,0 +1,64 @@
/** @defgroup comp_file COMP
*
* @ingroup STM32F0xx
*
* @brief <b>libopencm3 STM32F0xx COMP</b>
*
* @version 1.0.0
*
* @date 10 July 2013
*
* 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/comparator.h>
void comp_enable(uint8_t id)
{
COMP_CSR(id) |= COMP_CSR_EN;
}
void comp_disable(uint8_t id)
{
COMP_CSR(id) &= ~COMP_CSR_EN;
}
void comp_select_input(uint8_t id, uint32_t input)
{
COMP_CSR(id) = (COMP_CSR(id) & ~COMP_CSR_INSEL) | input;
}
void comp_select_output(uint8_t id, uint32_t output)
{
COMP_CSR(id) = (COMP_CSR(id) & ~COMP_CSR_OUTSEL) | output;
}
void comp_select_hyst(uint8_t id, uint32_t hyst)
{
COMP_CSR(id) = (COMP_CSR(id) & ~COMP_CSR_HYST) | hyst;
}
void comp_select_speed(uint8_t id, uint32_t speed)
{
COMP_CSR(id) = (COMP_CSR(id) & ~COMP_CSR_SPEED) | speed;
}
/**@}*/

View File

@@ -0,0 +1,156 @@
/** @defgroup flash_file FLASH peripheral API
*
* @ingroup peripheral_apis
*
* @brief <b>libopencm3 STM32F05x FLASH</b>
*
* @version 1.0.0
*
* @author @htmlonly &copy; @endhtmlonly 2013
* Frantisek Burian <BuFran@seznam.cz>
*
* @date 14 January 2014
*
* For the STM32F05x, accessing FLASH memory is described in
* section 3 of the STM32F05x Reference Manual.
*
* FLASH memory may be used for data storage as well as code, and may be
* programmatically modified. Note that for firmware upload the STM32F1xx
* provides a built-in bootloader in system memory that can be entered from a
* running program.
*
* FLASH must first be unlocked before programming. In this module a write to
* FLASH is a blocking operation until the end-of-operation flag is asserted.
*
* @note: don't forget to lock it again when all operations are complete.
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2013 Frantisek Burian <BuFran@seznam.cz>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/flash.h>
/*---------------------------------------------------------------------------*/
/** @brief Clear All Status Flags
Program error, end of operation, write protect error, busy.
*/
void flash_clear_status_flags(void)
{
flash_clear_pgerr_flag();
flash_clear_eop_flag();
flash_clear_wrprterr_flag();
}
/*---------------------------------------------------------------------------*/
/** @brief Read All Status Flags
The programming error, end of operation, write protect error and busy flags
are returned in the order of appearance in the status register.
@returns uint32_t. bit 0: busy, bit 2: programming error, bit 4: write protect
error, bit 5: end of operation.
*/
uint32_t flash_get_status_flags(void)
{
return FLASH_SR & (FLASH_SR_PGERR |
FLASH_SR_EOP |
FLASH_SR_WRPRTERR |
FLASH_SR_BSY);
}
/*---------------------------------------------------------------------------*/
/** @brief Program a Half Word to FLASH
This performs all operations necessary to program a 16 bit word to FLASH memory.
The program error flag should be checked separately for the event that memory
was not properly erased.
Status bit polling is used to detect end of operation.
@param[in] address Full address of flash half word to be programmed.
@param[in] data half word to write
*/
void flash_program_half_word(uint32_t address, uint16_t data)
{
flash_wait_for_last_operation();
FLASH_CR |= FLASH_CR_PG;
MMIO16(address) = data;
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_PG;
}
/*---------------------------------------------------------------------------*/
/** @brief Erase a Page of FLASH
This performs all operations necessary to erase a page in FLASH memory.
The page should be checked to ensure that it was properly erased. A page must
first be fully erased before attempting to program it.
Note that the page sizes differ between devices. See the reference manual or
the FLASH programming manual for details.
@param[in] page_address Full address of flash page to be erased.
*/
void flash_erase_page(uint32_t page_address)
{
flash_wait_for_last_operation();
FLASH_CR |= FLASH_CR_PER;
FLASH_AR = page_address;
FLASH_CR |= FLASH_CR_STRT;
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_PER;
}
/*---------------------------------------------------------------------------*/
/** @brief Erase All FLASH
This performs all operations necessary to erase all user pages in the FLASH
memory. The information block is unaffected.
*/
void flash_erase_all_pages(void)
{
flash_wait_for_last_operation();
FLASH_CR |= FLASH_CR_MER; /* Enable mass erase. */
FLASH_CR |= FLASH_CR_STRT; /* Trigger the erase. */
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_MER; /* Disable mass erase. */
}
/**@}*/

View File

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

View File

@@ -0,0 +1,699 @@
/** @defgroup rcc_file RCC peripheral API
*
* @ingroup peripheral_apis
*
* @brief <b>libopencm3 STM32F0xx Reset and Clock Control</b>
*
* @version 1.0.0
*
* @date 29 Jun 2013
*
* This library supports the Reset and Clock Control System in the STM32F0xx
* series of ARM Cortex Microcontrollers by ST Microelectronics.
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Federico Ruiz-Ugalde <memeruiz at gmail dot com>
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/cm3/assert.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/flash.h>
#include <libopencm3/stm32/i2c.h>
/* Set the default clock frequencies */
uint32_t rcc_ahb_frequency = 8000000; /* 8MHz after reset */
uint32_t rcc_apb1_frequency = 8000000; /* 8MHz after reset */
/*---------------------------------------------------------------------------*/
/** @brief RCC Clear the Oscillator Ready Interrupt Flag
*
* Clear the interrupt flag that was set when a clock oscillator became ready
* to use.
*
* @param osc Oscillator ID
*/
void rcc_osc_ready_int_clear(enum rcc_osc osc)
{
switch (osc) {
case RCC_HSI48:
RCC_CIR |= RCC_CIR_HSI48RDYC;
break;
case RCC_HSI14:
RCC_CIR |= RCC_CIR_HSI14RDYC;
break;
case RCC_HSI:
RCC_CIR |= RCC_CIR_HSIRDYC;
break;
case RCC_HSE:
RCC_CIR |= RCC_CIR_HSERDYC;
break;
case RCC_PLL:
RCC_CIR |= RCC_CIR_PLLRDYC;
break;
case RCC_LSE:
RCC_CIR |= RCC_CIR_LSERDYC;
break;
case RCC_LSI:
RCC_CIR |= RCC_CIR_LSIRDYC;
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Enable the Oscillator Ready Interrupt
*
* @param osc Oscillator ID
*/
void rcc_osc_ready_int_enable(enum rcc_osc osc)
{
switch (osc) {
case RCC_HSI48:
RCC_CIR |= RCC_CIR_HSI48RDYIE;
break;
case RCC_HSI14:
RCC_CIR |= RCC_CIR_HSI14RDYIE;
break;
case RCC_HSI:
RCC_CIR |= RCC_CIR_HSIRDYIE;
break;
case RCC_HSE:
RCC_CIR |= RCC_CIR_HSERDYIE;
break;
case RCC_PLL:
RCC_CIR |= RCC_CIR_PLLRDYIE;
break;
case RCC_LSE:
RCC_CIR |= RCC_CIR_LSERDYIE;
break;
case RCC_LSI:
RCC_CIR |= RCC_CIR_LSIRDYIE;
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Disable the Oscillator Ready Interrupt
*
* @param osc Oscillator ID
*/
void rcc_osc_ready_int_disable(enum rcc_osc osc)
{
switch (osc) {
case RCC_HSI48:
RCC_CIR &= ~RCC_CIR_HSI48RDYC;
break;
case RCC_HSI14:
RCC_CIR &= ~RCC_CIR_HSI14RDYC;
break;
case RCC_HSI:
RCC_CIR &= ~RCC_CIR_HSIRDYC;
break;
case RCC_HSE:
RCC_CIR &= ~RCC_CIR_HSERDYC;
break;
case RCC_PLL:
RCC_CIR &= ~RCC_CIR_PLLRDYC;
break;
case RCC_LSE:
RCC_CIR &= ~RCC_CIR_LSERDYC;
break;
case RCC_LSI:
RCC_CIR &= ~RCC_CIR_LSIRDYC;
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Read the Oscillator Ready Interrupt Flag
*
* @param osc Oscillator ID
* @returns int. Boolean value for flag set.
*/
int rcc_osc_ready_int_flag(enum rcc_osc osc)
{
switch (osc) {
case RCC_HSI48:
return (RCC_CIR & RCC_CIR_HSI48RDYF) != 0;
break;
case RCC_HSI14:
return (RCC_CIR & RCC_CIR_HSI14RDYF) != 0;
break;
case RCC_HSI:
return (RCC_CIR & RCC_CIR_HSIRDYF) != 0;
break;
case RCC_HSE:
return (RCC_CIR & RCC_CIR_HSERDYF) != 0;
break;
case RCC_PLL:
return (RCC_CIR & RCC_CIR_PLLRDYF) != 0;
break;
case RCC_LSE:
return (RCC_CIR & RCC_CIR_LSERDYF) != 0;
break;
case RCC_LSI:
return (RCC_CIR & RCC_CIR_LSIRDYF) != 0;
break;
}
cm3_assert_not_reached();
}
/*---------------------------------------------------------------------------*/
/** @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);
}
bool rcc_is_osc_ready(enum rcc_osc osc)
{
switch (osc) {
case RCC_HSI48:
return RCC_CR2 & RCC_CR2_HSI48RDY;
case RCC_HSI14:
return RCC_CR2 & RCC_CR2_HSI14RDY;
case RCC_HSI:
return RCC_CR & RCC_CR_HSIRDY;
case RCC_HSE:
return RCC_CR & RCC_CR_HSERDY;
case RCC_PLL:
return RCC_CR & RCC_CR_PLLRDY;
case RCC_LSE:
return RCC_BDCR & RCC_BDCR_LSERDY;
case RCC_LSI:
return RCC_CSR & RCC_CSR_LSIRDY;
}
return false;
}
void rcc_wait_for_osc_ready(enum rcc_osc osc)
{
while (!rcc_is_osc_ready(osc));
}
/*---------------------------------------------------------------------------*/
/** @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).
*
* @param osc Oscillator ID
*/
void rcc_osc_on(enum rcc_osc osc)
{
switch (osc) {
case RCC_HSI48:
RCC_CR2 |= RCC_CR2_HSI48ON;
break;
case RCC_HSI14:
RCC_CR2 |= RCC_CR2_HSI14ON;
break;
case RCC_HSI:
RCC_CR |= RCC_CR_HSION;
break;
case RCC_HSE:
RCC_CR |= RCC_CR_HSEON;
break;
case RCC_LSE:
RCC_BDCR |= RCC_BDCR_LSEON;
break;
case RCC_LSI:
RCC_CSR |= RCC_CSR_LSION;
break;
case RCC_PLL:
RCC_CR |= RCC_CR_PLLON;
break;
}
}
/*---------------------------------------------------------------------------*/
/** @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.
*
* @param osc Oscillator ID
*/
void rcc_osc_off(enum rcc_osc osc)
{
switch (osc) {
case RCC_HSI48:
RCC_CR2 &= ~RCC_CR2_HSI48ON;
break;
case RCC_HSI14:
RCC_CR2 &= ~RCC_CR2_HSI14ON;
break;
case RCC_HSI:
RCC_CR &= ~RCC_CR_HSION;
break;
case RCC_HSE:
RCC_CR &= ~RCC_CR_HSEON;
break;
case RCC_LSE:
RCC_BDCR &= ~RCC_BDCR_LSEON;
break;
case RCC_LSI:
RCC_CSR &= ~RCC_CSR_LSION;
break;
case RCC_PLL:
/* don't do anything */
break;
}
}
/*---------------------------------------------------------------------------*/
/** @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 Set the Source for the System Clock.
*
* @param clk Oscillator ID. Only HSE, LSE and PLL have
* effect.
*/
void rcc_set_sysclk_source(enum rcc_osc clk)
{
switch (clk) {
case RCC_HSI:
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSI;
break;
case RCC_HSE:
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSE;
break;
case RCC_PLL:
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_PLL;
break;
case RCC_HSI48:
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSI48;
break;
case RCC_LSI:
case RCC_LSE:
case RCC_HSI14:
/* do nothing */
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Set the Source for the USB Clock.
*
* @param clk Oscillator ID. Only HSI48 or PLL have
* effect.
*/
void rcc_set_usbclk_source(enum rcc_osc clk)
{
switch (clk) {
case RCC_PLL:
RCC_CFGR3 |= RCC_CFGR3_USBSW;
break;
case RCC_HSI48:
RCC_CFGR3 &= ~RCC_CFGR3_USBSW;
break;
case RCC_HSI:
case RCC_HSE:
case RCC_LSI:
case RCC_LSE:
case RCC_HSI14:
/* do nothing */
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Enable the RTC clock
*/
void rcc_enable_rtc_clock(void)
{
RCC_BDCR |= RCC_BDCR_RTCEN;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Disable the RTC clock
*/
void rcc_disable_rtc_clock(void)
{
RCC_BDCR &= ~RCC_BDCR_RTCEN;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Set the Source for the RTC clock
@param[in] clk RTC clock source. Only HSE/32, LSE and LSI.
*/
void rcc_set_rtc_clock_source(enum rcc_osc clk)
{
switch (clk) {
case RCC_HSE:
RCC_BDCR = (RCC_BDCR & ~RCC_BDCR_RTCSEL) | RCC_BDCR_RTCSEL_HSE;
break;
case RCC_LSE:
RCC_BDCR = (RCC_BDCR & ~RCC_BDCR_RTCSEL) | RCC_BDCR_RTCSEL_LSE;
break;
case RCC_LSI:
RCC_BDCR = (RCC_BDCR & ~RCC_BDCR_RTCSEL) | RCC_BDCR_RTCSEL_LSI;
break;
default:
/* do nothing */
break;
}
}
/*---------------------------------------------------------------------------*/
/** @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(uint32_t mul)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PLLMUL) | mul;
}
/*---------------------------------------------------------------------------*/
/** @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(uint32_t pllsrc)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PLLSRC) |
(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(uint32_t pllxtpre)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PLLXTPRE) |
(pllxtpre << 17);
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Set the APB Prescale Factor.
*
* @param[in] ppre Unsigned int32. APB prescale factor @ref rcc_cfgr_apb1pre
*/
void rcc_set_ppre(uint32_t ppre)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PPRE) | ppre;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Set the AHB Prescale Factor.
*
* @param[in] hpre Unsigned int32. AHB prescale factor @ref rcc_cfgr_ahbpre
*/
void rcc_set_hpre(uint32_t hpre)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_HPRE) | hpre;
}
/**
* Set PLL Source pre-divider **CAUTION**.
* On F03x and F05, prediv only applies to HSE source. On others, this
* is _after_ source selection. See also f3.
* @param[in] prediv division by prediv+1 @ref rcc_cfgr2_prediv
*/
void rcc_set_prediv(uint32_t prediv)
{
RCC_CFGR2 = (RCC_CFGR2 & ~RCC_CFGR2_PREDIV) | prediv;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Get the System Clock Source.
*
* @returns current system clock source
*/
enum rcc_osc rcc_system_clock_source(void)
{
/* Return the clock source which is used as system clock. */
switch (RCC_CFGR & RCC_CFGR_SWS) {
case RCC_CFGR_SWS_HSI:
return RCC_HSI;
case RCC_CFGR_SWS_HSE:
return RCC_HSE;
case RCC_CFGR_SWS_PLL:
return RCC_PLL;
case RCC_CFGR_SWS_HSI48:
return RCC_HSI48;
}
cm3_assert_not_reached();
}
void rcc_set_i2c_clock_hsi(uint32_t i2c)
{
if (i2c == I2C1) {
RCC_CFGR3 &= ~RCC_CFGR3_I2C1SW;
}
}
void rcc_set_i2c_clock_sysclk(uint32_t i2c)
{
if (i2c == I2C1) {
RCC_CFGR3 |= RCC_CFGR3_I2C1SW;
}
}
uint32_t rcc_get_i2c_clocks(void)
{
return RCC_CFGR3 & RCC_CFGR3_I2C1SW;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Get the USB Clock Source.
*
* @returns Currently selected USB clock source
*/
enum rcc_osc rcc_usb_clock_source(void)
{
return (RCC_CFGR3 & RCC_CFGR3_USBSW) ? RCC_PLL : RCC_HSI48;
}
/**
* Set System Clock PLL at 48MHz from HSE at 8MHz.
*/
void rcc_clock_setup_in_hse_8mhz_out_48mhz(void)
{
rcc_osc_on(RCC_HSE);
rcc_wait_for_osc_ready(RCC_HSE);
rcc_set_sysclk_source(RCC_HSE);
rcc_set_hpre(RCC_CFGR_HPRE_NODIV);
rcc_set_ppre(RCC_CFGR_PPRE_NODIV);
flash_prefetch_enable();
flash_set_ws(FLASH_ACR_LATENCY_024_048MHZ);
/* PLL: 8MHz * 6 = 48MHz */
rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL6);
rcc_set_pll_source(RCC_CFGR_PLLSRC_HSE_CLK);
rcc_set_pllxtpre(RCC_CFGR_PLLXTPRE_HSE_CLK);
rcc_osc_on(RCC_PLL);
rcc_wait_for_osc_ready(RCC_PLL);
rcc_set_sysclk_source(RCC_PLL);
rcc_apb1_frequency = 48000000;
rcc_ahb_frequency = 48000000;
}
/**
* Set System Clock PLL at 48MHz from HSI
*/
void rcc_clock_setup_in_hsi_out_48mhz(void)
{
rcc_osc_on(RCC_HSI);
rcc_wait_for_osc_ready(RCC_HSI);
rcc_set_sysclk_source(RCC_HSI);
rcc_set_hpre(RCC_CFGR_HPRE_NODIV);
rcc_set_ppre(RCC_CFGR_PPRE_NODIV);
flash_prefetch_enable();
flash_set_ws(FLASH_ACR_LATENCY_024_048MHZ);
/* 8MHz * 12 / 2 = 48MHz */
rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL12);
rcc_set_pll_source(RCC_CFGR_PLLSRC_HSI_CLK_DIV2);
rcc_osc_on(RCC_PLL);
rcc_wait_for_osc_ready(RCC_PLL);
rcc_set_sysclk_source(RCC_PLL);
rcc_apb1_frequency = 48000000;
rcc_ahb_frequency = 48000000;
}
/**
* Set System Clock HSI48 at 48MHz
*/
void rcc_clock_setup_in_hsi48_out_48mhz(void)
{
rcc_osc_on(RCC_HSI48);
rcc_wait_for_osc_ready(RCC_HSI48);
rcc_set_hpre(RCC_CFGR_HPRE_NODIV);
rcc_set_ppre(RCC_CFGR_PPRE_NODIV);
flash_prefetch_enable();
flash_set_ws(FLASH_ACR_LATENCY_024_048MHZ);
rcc_set_sysclk_source(RCC_HSI48);
rcc_apb1_frequency = 48000000;
rcc_ahb_frequency = 48000000;
}
static uint32_t rcc_get_usart_clksel_freq(uint8_t shift) {
uint8_t clksel = (RCC_CFGR3 >> shift) & RCC_CFGR3_USARTxSW_MASK;
uint8_t hpre = (RCC_CFGR >> RCC_CFGR_HPRE_SHIFT) & RCC_CFGR_HPRE_MASK;
switch (clksel) {
case RCC_CFGR3_USARTxSW_PCLK:
return rcc_apb1_frequency;
case RCC_CFGR3_USARTxSW_SYSCLK:
return rcc_ahb_frequency * rcc_get_div_from_hpre(hpre);
case RCC_CFGR3_USARTxSW_LSE:
return 32768;
case RCC_CFGR3_USARTxSW_HSI:
return 8000000U;
}
cm3_assert_not_reached();
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the USART at base specified.
* @param usart Base address of USART to get clock frequency for.
*/
uint32_t rcc_get_usart_clk_freq(uint32_t usart)
{
if (usart == USART1_BASE) {
return rcc_get_usart_clksel_freq(RCC_CFGR3_USART1SW_SHIFT);
} else if (usart == USART2_BASE) {
return rcc_get_usart_clksel_freq(RCC_CFGR3_USART2SW_SHIFT);
} else if (usart == USART3_BASE) {
return rcc_get_usart_clksel_freq(RCC_CFGR3_USART3SW_SHIFT);
} else {
return rcc_apb1_frequency;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the Timer at base specified.
* @param timer Base address of TIM to get clock frequency for.
*/
uint32_t rcc_get_timer_clk_freq(uint32_t timer __attribute__((unused)))
{
uint8_t ppre = (RCC_CFGR >> RCC_CFGR_PPRE_SHIFT) & RCC_CFGR_PPRE_MASK;
return (ppre == RCC_CFGR_PPRE_NODIV) ? rcc_apb1_frequency
: 2 * rcc_apb1_frequency;
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the I2C device at base specified.
* @param i2c Base address of I2C to get clock frequency for.
*/
uint32_t rcc_get_i2c_clk_freq(uint32_t i2c)
{
if (i2c == I2C1_BASE) {
if (RCC_CFGR3 & RCC_CFGR3_I2C1SW) {
uint8_t hpre = (RCC_CFGR >> RCC_CFGR_HPRE_SHIFT) & RCC_CFGR_HPRE_MASK;
return rcc_ahb_frequency * rcc_get_div_from_hpre(hpre);
} else {
return 8000000U;
}
} else {
return rcc_apb1_frequency;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the SPI device at base specified.
* @param spi Base address of SPI device to get clock frequency for (e.g. SPI1_BASE).
*/
uint32_t rcc_get_spi_clk_freq(uint32_t spi __attribute__((unused))) {
return rcc_apb1_frequency;
}
/**@}*/

View File

@@ -0,0 +1,31 @@
/** @defgroup syscfg_file SYSCFG
*
* @ingroup STM32F0xx
*
* @brief <b>libopencm3 STM32F0xx SYSCFG</b>
*
* @version 1.0.0
*
* @date 10 July 2013
*
* 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/syscfg.h>

View File

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

View File

@@ -0,0 +1,443 @@
/** @addtogroup adc_file ADC peripheral API
@ingroup peripheral_apis
@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
(default). Enable triggering for a software trigger.
@code
rcc_periph_clock_enable(RCC_ADC1);
adc_power_off(ADC1);
rcc_periph_reset_pulse(RST_ADC1);
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_SMPR_SMP_1DOT5CYC);
adc_enable_external_trigger_regular(ADC1, ADC_CR2_EXTSEL_SWSTART);
adc_power_on(ADC1);
adc_reset_calibration(ADC1);
adc_calibrate(ADC1);
adc_start_conversion_regular(ADC1);
while (! adc_eoc(ADC1));
reg16 = adc_read_regular(ADC1);
@endcode
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Edward Cheeseman <evbuilder@users.sourceforge.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/adc.h>
/*---------------------------------------------------------------------------*/
/** @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 has no effect.
* NOTE Common with F37x
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_power_on(uint32_t adc)
{
if (!(ADC_CR2(adc) & ADC_CR2_ADON)) {
ADC_CR2(adc) |= ADC_CR2_ADON;
}
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Start a Conversion Without Trigger
This initiates a conversion by software without a trigger. The ADC needs to be
powered on before this is called, otherwise this function has no effect.
Note that this is not available in other STM32F families. To ensure code
compatibility, enable triggering and use a software trigger source @see
adc_start_conversion_regular.
@param[in] adc Unsigned int32. ADC block register address base @ref adc_reg_base
*/
void adc_start_conversion_direct(uint32_t adc)
{
if (ADC_CR2(adc) & ADC_CR2_ADON) {
ADC_CR2(adc) |= ADC_CR2_ADON;
}
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set Dual A/D Mode
The dual mode uses ADC1 as master and ADC2 in a slave arrangement. This setting
is applied to ADC1 only. Start of conversion when triggered can cause
simultaneous conversion with ADC2, or alternate conversion. Regular and
injected conversions can be configured, each one being separately simultaneous
or alternate.
Fast interleaved mode starts ADC1 immediately on trigger, and ADC2 seven clock
cycles later.
Slow interleaved mode starts ADC1 immediately on trigger, and ADC2 fourteen
clock cycles later, followed by ADC1 fourteen cycles later again. This can only
be used on a single channel.
Alternate trigger mode must occur on an injected channel group, and alternates
between the ADCs on each trigger.
Note that sampling must not overlap between ADCs on the same channel.
Dual A/D converter modes possible:
@li IND: Independent mode.
@li CRSISM: Combined regular simultaneous + injected simultaneous mode.
@li CRSATM: Combined regular simultaneous + alternate trigger mode.
@li CISFIM: Combined injected simultaneous + fast interleaved mode.
@li CISSIM: Combined injected simultaneous + slow interleaved mode.
@li ISM: Injected simultaneous mode only.
@li RSM: Regular simultaneous mode only.
@li FIM: Fast interleaved mode only.
@li SIM: Slow interleaved mode only.
@li ATM: Alternate trigger mode only.
@param[in] mode Unsigned int32. Dual mode selection from @ref adc_cr1_dualmod
*/
void adc_set_dual_mode(uint32_t mode)
{
ADC1_CR1 |= mode;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable The Temperature Sensor
This enables both the sensor and the reference voltage measurements on channels
16 and 17.
*/
void adc_enable_temperature_sensor()
{
ADC_CR2(ADC1) |= ADC_CR2_TSVREFE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable The Temperature Sensor
Disabling this will reduce power consumption from the sensor and the reference
voltage measurements.
*/
void adc_disable_temperature_sensor()
{
ADC_CR2(ADC1) &= ~ADC_CR2_TSVREFE;
}
/*---------------------------------------------------------------------------*/
/** @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(uint32_t adc, uint32_t trigger)
{
uint32_t reg32;
reg32 = (ADC_CR2(adc) & ~(ADC_CR2_EXTSEL_MASK));
reg32 |= (trigger);
ADC_CR2(adc) = reg32;
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(uint32_t 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(uint32_t adc, uint32_t trigger)
{
uint32_t reg32;
reg32 = (ADC_CR2(adc) & ~(ADC_CR2_JEXTSEL_MASK)); /* Clear bits [12:14]
*/
reg32 |= (trigger);
ADC_CR2(adc) = reg32;
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(uint32_t adc)
{
ADC_CR2(adc) &= ~ADC_CR2_JEXTTRIG;
}
/*---------------------------------------------------------------------------*/
/** @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(uint32_t adc)
{
ADC_CR2(adc) |= ADC_CR2_RSTCAL;
while (ADC_CR2(adc) & ADC_CR2_RSTCAL);
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Calibration
@deprecated replaced by adc_calibrate/_async/_is_calibrating
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(uint32_t adc)
{
ADC_CR2(adc) |= ADC_CR2_CAL;
while (ADC_CR2(adc) & ADC_CR2_CAL);
}
/**
* Start the ADC calibration and immediately return.
* @sa adc_calibrate
* @sa adc_is_calibrate
* @param adc ADC Block register address base @ref adc_reg_base
*/
void adc_calibrate_async(uint32_t adc)
{
ADC_CR2(adc) |= ADC_CR2_CAL;
}
/**
* Is the ADC Calibrating?
* @param adc ADC Block register address base @ref adc_reg_base
* @return true if the adc is currently calibrating
*/
bool adc_is_calibrating(uint32_t adc)
{
return (ADC_CR2(adc) & ADC_CR2_CAL);
}
/**
* Start ADC calibration and wait for it to finish.
* The ADC must have been powered down for at least 2 ADC clock cycles, then
* powered on before calibration starts
* @param adc ADC Block register address base @ref adc_reg_base
*/
void adc_calibrate(uint32_t adc)
{
adc_calibrate_async(adc);
while (adc_is_calibrating(adc));
}
/*---------------------------------------------------------------------------*/
/** @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.
* * NOTE Common with f2 and f37x and f4
*/
void adc_set_sample_time(uint32_t adc, uint8_t channel, uint8_t time)
{
uint32_t reg32;
if (channel < 10) {
reg32 = ADC_SMPR2(adc);
reg32 &= ~(0x7 << (channel * 3));
reg32 |= (time << (channel * 3));
ADC_SMPR2(adc) = reg32;
} else {
reg32 = ADC_SMPR1(adc);
reg32 &= ~(0x7 << ((channel - 10) * 3));
reg32 |= (time << ((channel - 10) * 3));
ADC_SMPR1(adc) = reg32;
}
}
/*---------------------------------------------------------------------------*/
/** @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.
* * NOTE Common with f2 and f37x and f4
*/
void adc_set_sample_time_on_all_channels(uint32_t adc, uint8_t time)
{
uint8_t i;
uint32_t reg32 = 0;
for (i = 0; i <= 9; i++) {
reg32 |= (time << (i * 3));
}
ADC_SMPR2(adc) = reg32;
for (i = 10; i <= 17; i++) {
reg32 |= (time << ((i - 10) * 3));
}
ADC_SMPR1(adc) = reg32;
}
/*---------------------------------------------------------------------------*/
/**@}*/

View File

@@ -0,0 +1,303 @@
/** @defgroup flash_file FLASH peripheral API
*
* @ingroup peripheral_apis
*
* @brief <b>libopencm3 STM32F1xx FLASH Memory</b>
*
* @version 1.0.0
*
* @author @htmlonly &copy; @endhtmlonly 2010
* Thomas Otto <tommi@viadmin.org>
* @author @htmlonly &copy; @endhtmlonly 2010
* Mark Butler <mbutler@physics.otago.ac.nz>
*
* @date 14 January 2014
*
* For the STM32F1xx, accessing FLASH memory is described briefly in
* section 3.3.3 of the STM32F10x Reference Manual.
* For detailed programming information see:
* PM0075 programming manual: STM32F10xxx Flash programming
* August 2010, Doc ID 17863 Rev 1
* https://github.com/libopencm3/libopencm3-archive/blob/master/st_micro/CD00283419.pdf
*
* FLASH memory may be used for data storage as well as code, and may be
* programmatically modified. Note that for firmware upload the STM32F1xx
* provides a built-in bootloader in system memory that can be entered from a
* running program.
*
* FLASH must first be unlocked before programming. In this module a write to
* FLASH is a blocking operation until the end-of-operation flag is asserted.
*
* @note: don't forget to lock it again when all operations are complete.
*
* For the large memory XL series, with two banks of FLASH, the upper bank is
* accessed with a second set of registers. In principle both banks can be
* written simultaneously, or one read while the other is written. This module
* does not support the simultaneous write feature.
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
*
* 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/desig.h>
#include <libopencm3/stm32/flash.h>
/*---------------------------------------------------------------------------*/
/** @brief Enable the FLASH Half Cycle Mode
This mode is used for power saving during read access. It is disabled by default
on reset.
Note carefully the clock restrictions under which the half cycle mode may be
enabled or disabled. This mode may only be used while the clock is running at
8MHz. See the reference manual for details.
*/
void flash_halfcycle_enable(void)
{
FLASH_ACR |= FLASH_ACR_HLFCYA;
}
/*---------------------------------------------------------------------------*/
/** @brief Disable the FLASH Half Cycle Mode
*/
void flash_halfcycle_disable(void)
{
FLASH_ACR &= ~FLASH_ACR_HLFCYA;
}
/*---------------------------------------------------------------------------*/
/** @brief Unlock the Flash Program and Erase Controller, upper Bank
This enables write access to the upper bank of the Flash memory in XL devices.
It is locked by default on reset.
*/
void flash_unlock_upper(void)
{
if (desig_get_flash_size() > 512) {
/* Clear the unlock state. */
FLASH_CR2 |= FLASH_CR_LOCK;
/* Authorize the FPEC access. */
FLASH_KEYR2 = FLASH_KEYR_KEY1;
FLASH_KEYR2 = FLASH_KEYR_KEY2;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Lock the Flash Program and Erase Controller, upper Bank
Used to prevent spurious writes to FLASH.
*/
void flash_lock_upper(void)
{
FLASH_CR2 |= FLASH_CR_LOCK;
}
/*---------------------------------------------------------------------------*/
/** @brief Clear the Programming Error Status Flag, upper Bank
*/
void flash_clear_pgerr_flag_upper(void)
{
if (desig_get_flash_size() > 512) {
FLASH_SR2 |= FLASH_SR_PGERR;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Clear the End of Operation Status Flag, upper Bank
*/
void flash_clear_eop_flag_upper(void)
{
if (desig_get_flash_size() > 512) {
FLASH_SR2 |= FLASH_SR_EOP;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Clear the Write Protect Error Status Flag, upper Bank
*/
void flash_clear_wrprterr_flag_upper(void)
{
if (desig_get_flash_size() > 512) {
FLASH_SR2 |= FLASH_SR_WRPRTERR;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Clear All Status Flags
Program error, end of operation, write protect error, busy. Both banks cleared.
*/
void flash_clear_status_flags(void)
{
flash_clear_pgerr_flag();
flash_clear_eop_flag();
flash_clear_wrprterr_flag();
if (desig_get_flash_size() > 512) {
flash_clear_pgerr_flag_upper();
flash_clear_eop_flag_upper();
flash_clear_wrprterr_flag_upper();
}
}
/*---------------------------------------------------------------------------*/
/** @brief Read All Status Flags
The programming error, end of operation, write protect error and busy flags
are returned in the order of appearance in the status register.
Flags for the upper bank, where appropriate, are combined with those for
the lower bank using bitwise OR, without distinction.
@returns uint32_t. bit 0: busy, bit 2: programming error, bit 4: write protect
error, bit 5: end of operation.
*/
uint32_t flash_get_status_flags(void)
{
uint32_t flags = (FLASH_SR & (FLASH_SR_PGERR |
FLASH_SR_EOP |
FLASH_SR_WRPRTERR |
FLASH_SR_BSY));
if (desig_get_flash_size() > 512) {
flags |= (FLASH_SR2 & (FLASH_SR_PGERR |
FLASH_SR_EOP |
FLASH_SR_WRPRTERR |
FLASH_SR_BSY));
}
return flags;
}
/*---------------------------------------------------------------------------*/
/** @brief Program a Half Word to FLASH
This performs all operations necessary to program a 16 bit word to FLASH memory.
The program error flag should be checked separately for the event that memory
was not properly erased.
Status bit polling is used to detect end of operation.
@param[in] address Full address of flash half word to be programmed.
@param[in] data half word to write
*/
void flash_program_half_word(uint32_t address, uint16_t data)
{
flash_wait_for_last_operation();
if ((desig_get_flash_size() > 512) && (address >= FLASH_BASE+0x00080000)) {
FLASH_CR2 |= FLASH_CR_PG;
} else {
FLASH_CR |= FLASH_CR_PG;
}
MMIO16(address) = data;
flash_wait_for_last_operation();
if ((desig_get_flash_size() > 512) && (address >= FLASH_BASE+0x00080000)) {
FLASH_CR2 &= ~FLASH_CR_PG;
} else {
FLASH_CR &= ~FLASH_CR_PG;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Erase a Page of FLASH
This performs all operations necessary to erase a page in FLASH memory.
The page should be checked to ensure that it was properly erased. A page must
first be fully erased before attempting to program it.
Note that the page sizes differ between devices. See the reference manual or
the FLASH programming manual for details.
@param[in] page_address Full address of flash page to be erased.
*/
void flash_erase_page(uint32_t page_address)
{
flash_wait_for_last_operation();
if ((desig_get_flash_size() > 512)
&& (page_address >= FLASH_BASE+0x00080000)) {
FLASH_CR2 |= FLASH_CR_PER;
FLASH_AR2 = page_address;
FLASH_CR2 |= FLASH_CR_STRT;
} else {
FLASH_CR |= FLASH_CR_PER;
FLASH_AR = page_address;
FLASH_CR |= FLASH_CR_STRT;
}
flash_wait_for_last_operation();
if ((desig_get_flash_size() > 512)
&& (page_address >= FLASH_BASE+0x00080000)) {
FLASH_CR2 &= ~FLASH_CR_PER;
} else {
FLASH_CR &= ~FLASH_CR_PER;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Erase All FLASH
This performs all operations necessary to erase all user pages in the FLASH
memory. The information block is unaffected.
*/
void flash_erase_all_pages(void)
{
flash_wait_for_last_operation();
FLASH_CR |= FLASH_CR_MER; /* Enable mass erase. */
FLASH_CR |= FLASH_CR_STRT; /* Trigger the erase. */
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_MER; /* Disable mass erase. */
/* Repeat for bank 2 */
FLASH_CR2 |= FLASH_CR_MER;
FLASH_CR2 |= FLASH_CR_STRT;
flash_wait_for_last_operation();
FLASH_CR2 &= ~FLASH_CR_MER;
}
/**@}*/

View File

@@ -0,0 +1,198 @@
/** @addtogroup gpio_file
@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
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_FLOAT, GPIO12);
reg16 = gpio_port_read(GPIOC);
@endcode
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/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 bitwise OR '|' to separate
them.
*/
void gpio_set_mode(uint32_t gpioport, uint8_t mode, uint8_t cnf, uint16_t gpios)
{
uint16_t i, offset = 0;
uint32_t crl = 0, crh = 0, tmp32 = 0;
/*
* We want to set the config only for the pins mentioned in gpios,
* but keeping the others, so read out the actual config first.
*/
crl = GPIO_CRL(gpioport);
crh = GPIO_CRH(gpioport);
/* Iterate over all bits, use i as the bitnumber. */
for (i = 0; i < 16; i++) {
/* Only set the config if the bit is set in gpios. */
if (!((1 << i) & gpios)) {
continue;
}
/* Calculate bit offset. */
offset = (i < 8) ? (i * 4) : ((i - 8) * 4);
/* Use tmp32 to either modify crl or crh. */
tmp32 = (i < 8) ? crl : crh;
/* Modify bits are needed. */
tmp32 &= ~(0xf << offset); /* Clear the bits first. */
tmp32 |= (mode << offset) | (cnf << (offset + 2));
/* Write tmp32 into crl or crh, leave the other unchanged. */
crl = (i < 8) ? tmp32 : crl;
crh = (i >= 8) ? tmp32 : crh;
}
GPIO_CRL(gpioport) = crl;
GPIO_CRH(gpioport) = crh;
}
/*---------------------------------------------------------------------------*/
/** @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(uint8_t evoutport, uint8_t 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 Disable parts of the SWJ capability @ref
afio_swj_disable.
@param[in] maps Bitwise OR of map enable controls you wish to
enable 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(uint32_t swjdisable, uint32_t maps)
{
/*
* the SWJ_CFG bits are write only. (read is explicitly undefined)
* To be sure we set only the bits we want we must clear them first.
* However, we are still trying to only enable the map bits desired.
*/
uint32_t reg = AFIO_MAPR & ~AFIO_MAPR_SWJ_MASK;
AFIO_MAPR = reg | swjdisable | maps;
}
/*---------------------------------------------------------------------------*/
/** @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. Bitwise OR of map enable controls from @ref
afio_remap2
*/
void gpio_secondary_remap(uint32_t maps)
{
AFIO_MAPR2 |= maps;
}
/**@}*/

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,418 @@
/** @defgroup rtc_file RTC peripheral API
*
* @ingroup peripheral_apis
*
* @brief <b>libopencm3 STM32F1xx RTC</b>
*
* @author @htmlonly &copy; @endhtmlonly 2010 Uwe Hermann <uwe@hermann-uwe.de>
* @author @htmlonly &copy; @endhtmlonly 2010 Lord James <lordjames@y7mail.com>
*
* @version 1.0.0
*
* @date 4 March 2013
*
* The Real Time Clock peripheral consists of a set of 16 bit control, status,
* prescaler, counter and alarm registers. Before the latter three can be
* written the RTC must be placed in configuration mode by a call to
* @ref rtc_enter_config_mode(). The functions below handle this implictly.
*
* The RTC is completely reset by performing a Backup Domain reset. Note
* that this can affect unrelated user data contained in the Backup Domain
* registers. Other forms of reset will not affect the RTC registers as they
* are contained within the backup domain.
*
* The RTC clock source to be used is selected by calling
* @ref rcc_set_rtc_clock_source().
*
* The LSE clock source normally comes from a 32.768kHz external crystal
* This clock is in the backup domain and so continues to run when only the
* V_BAT supply is present. A prescaler value of 7FFF will give a 1 second
* count quantum.
*
* The LSI clock source is a low accuracy internal clock of about 40kHz
* frequency, and the HSE clock source is the external high speed clock
* divided by 128.
*
* Initial configuration of the RTC consists of:
*
* @li perform a Backup Domain reset if appropriate;
* @li select the clock to be used;
* @li set the prescaler, counter and configuration values;
* @li enable the RTC.
*
* @note reading the RTC registers may result in a corrupted value being
* returned in certain cases. Refer to the STM32F1xx Reference Manual.
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2010 Lord James <lordjames@y7mail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/rtc.h>
#include <libopencm3/stm32/pwr.h>
/*---------------------------------------------------------------------------*/
/** @brief RTC Set Operational from the Off state.
Power up the backup domain clocks, enable write access to the backup domain,
select the clock source, clear the RTC registers and enable the RTC.
@param[in] clock_source ::rcc_osc. RTC clock source. Only the values HSE, LSE
and LSI are permitted.
*/
void rtc_awake_from_off(enum rcc_osc clock_source)
{
uint32_t reg32;
/* Enable power and backup interface clocks. */
rcc_periph_clock_enable(RCC_PWR);
rcc_periph_clock_enable(RCC_BKP);
/* Enable access to the backup registers and the RTC. */
pwr_disable_backup_domain_write_protect();
/* Set the clock source */
rcc_set_rtc_clock_source(clock_source);
/* Clear the RTC Control Register */
RTC_CRH = 0;
RTC_CRL = 0;
/* Enable the RTC. */
rcc_enable_rtc_clock();
/* Clear the Registers */
rtc_enter_config_mode();
RTC_PRLH = 0;
RTC_PRLL = 0;
RTC_CNTH = 0;
RTC_CNTL = 0;
RTC_ALRH = 0xFFFF;
RTC_ALRL = 0xFFFF;
rtc_exit_config_mode();
/* Wait for the RSF bit in RTC_CRL to be set by hardware. */
RTC_CRL &= ~RTC_CRL_RSF;
while ((reg32 = (RTC_CRL & RTC_CRL_RSF)) == 0);
}
/*---------------------------------------------------------------------------*/
/** @brief RTC Enter Configuration Mode.
Prime the RTC for configuration changes by giving access to the prescaler,
and counter and alarm registers.
*/
void rtc_enter_config_mode(void)
{
uint32_t reg32;
/* Wait until the RTOFF bit is 1 (no RTC register writes ongoing). */
while ((reg32 = (RTC_CRL & RTC_CRL_RTOFF)) == 0);
/* Enter configuration mode. */
RTC_CRL |= RTC_CRL_CNF;
}
/*---------------------------------------------------------------------------*/
/** @brief RTC Leave Configuration Mode.
Revert the RTC to operational state.
*/
void rtc_exit_config_mode(void)
{
uint32_t reg32;
/* Exit configuration mode. */
RTC_CRL &= ~RTC_CRL_CNF;
/* Wait until the RTOFF bit is 1 (our RTC register write finished). */
while ((reg32 = (RTC_CRL & RTC_CRL_RTOFF)) == 0);
}
/*---------------------------------------------------------------------------*/
/** @brief RTC Set the Alarm Time.
@param[in] alarm_time uint32_t. time at which the alarm event is triggered.
*/
void rtc_set_alarm_time(uint32_t alarm_time)
{
rtc_enter_config_mode();
RTC_ALRL = (alarm_time & 0x0000ffff);
RTC_ALRH = (alarm_time & 0xffff0000) >> 16;
rtc_exit_config_mode();
}
/*---------------------------------------------------------------------------*/
/** @brief RTC Enable the Alarm.
*/
void rtc_enable_alarm(void)
{
rtc_enter_config_mode();
RTC_CRH |= RTC_CRH_ALRIE;
rtc_exit_config_mode();
}
/*---------------------------------------------------------------------------*/
/** @brief RTC Disable the Alarm.
*/
void rtc_disable_alarm(void)
{
rtc_enter_config_mode();
RTC_CRH &= ~RTC_CRH_ALRIE;
rtc_exit_config_mode();
}
/*---------------------------------------------------------------------------*/
/** @brief RTC Set the prescaler Value
@param[in] prescale_val uint32_t. 20 bit prescale divider.
*/
void rtc_set_prescale_val(uint32_t prescale_val)
{
rtc_enter_config_mode();
RTC_PRLL = prescale_val & 0x0000ffff; /* PRL[15:0] */
RTC_PRLH = (prescale_val & 0x000f0000) >> 16; /* PRL[19:16] */
rtc_exit_config_mode();
}
/*---------------------------------------------------------------------------*/
/** @brief RTC return the Counter Value
@returns uint32_t: the 32 bit counter value.
*/
uint32_t rtc_get_counter_val(void)
{
return (RTC_CNTH << 16) | RTC_CNTL;
}
/*---------------------------------------------------------------------------*/
/** @brief RTC return the prescaler Value
@returns uint32_t: the 20 bit prescale divider.
*/
uint32_t rtc_get_prescale_div_val(void)
{
return (RTC_DIVH << 16) | RTC_DIVL;
}
/*---------------------------------------------------------------------------*/
/** @brief RTC return the Alarm Value
@returns uint32_t: the 32 bit alarm value.
*/
uint32_t rtc_get_alarm_val(void)
{
return (RTC_ALRH << 16) | RTC_ALRL;
}
/*---------------------------------------------------------------------------*/
/** @brief RTC set the Counter
@param[in] counter_val 32 bit time setting for the counter.
*/
void rtc_set_counter_val(uint32_t counter_val)
{
rtc_enter_config_mode();
RTC_CNTH = (counter_val & 0xffff0000) >> 16; /* CNT[31:16] */
RTC_CNTL = counter_val & 0x0000ffff; /* CNT[15:0] */
rtc_exit_config_mode();
}
/*---------------------------------------------------------------------------*/
/** @brief RTC Enable Interrupt
@param[in] flag_val ::rtcflag_t: The flag to enable.
*/
void rtc_interrupt_enable(rtcflag_t flag_val)
{
rtc_enter_config_mode();
/* Set the correct interrupt enable. */
switch (flag_val) {
case RTC_SEC:
RTC_CRH |= RTC_CRH_SECIE;
break;
case RTC_ALR:
RTC_CRH |= RTC_CRH_ALRIE;
break;
case RTC_OW:
RTC_CRH |= RTC_CRH_OWIE;
break;
}
rtc_exit_config_mode();
}
/*---------------------------------------------------------------------------*/
/** @brief RTC Disable Interrupt
@param[in] flag_val ::rtcflag_t: The flag to disable.
*/
void rtc_interrupt_disable(rtcflag_t flag_val)
{
rtc_enter_config_mode();
/* Disable the correct interrupt enable. */
switch (flag_val) {
case RTC_SEC:
RTC_CRH &= ~RTC_CRH_SECIE;
break;
case RTC_ALR:
RTC_CRH &= ~RTC_CRH_ALRIE;
break;
case RTC_OW:
RTC_CRH &= ~RTC_CRH_OWIE;
break;
}
rtc_exit_config_mode();
}
/*---------------------------------------------------------------------------*/
/** @brief RTC Clear an Interrupt Flag
@param[in] flag_val ::rtcflag_t: The flag to clear.
*/
void rtc_clear_flag(rtcflag_t flag_val)
{
/* Configuration mode not needed. */
/* Clear the correct flag. */
switch (flag_val) {
case RTC_SEC:
RTC_CRL &= ~RTC_CRL_SECF;
break;
case RTC_ALR:
RTC_CRL &= ~RTC_CRL_ALRF;
break;
case RTC_OW:
RTC_CRL &= ~RTC_CRL_OWF;
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RTC Return a Flag Setting
@param[in] flag_val ::rtcflag_t: The flag to check.
@returns uint32_t: a nonzero value if the flag is set, zero otherwise.
*/
uint32_t rtc_check_flag(rtcflag_t flag_val)
{
uint32_t reg32;
/* Read correct flag. */
switch (flag_val) {
case RTC_SEC:
reg32 = RTC_CRL & RTC_CRL_SECF;
break;
case RTC_ALR:
reg32 = RTC_CRL & RTC_CRL_ALRF;
break;
case RTC_OW:
reg32 = RTC_CRL & RTC_CRL_OWF;
break;
default:
reg32 = 0;
break;
}
return reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief RTC Start RTC after Standby Mode.
Enable the backup domain clocks, enable write access to the backup
domain and the RTC, and synchronise the RTC register access.
*/
void rtc_awake_from_standby(void)
{
uint32_t reg32;
/* Enable power and backup interface clocks. */
rcc_periph_clock_enable(RCC_PWR);
rcc_periph_clock_enable(RCC_BKP);
/* Enable access to the backup registers and the RTC. */
pwr_disable_backup_domain_write_protect();
/* Wait for the RSF bit in RTC_CRL to be set by hardware. */
RTC_CRL &= ~RTC_CRL_RSF;
while ((reg32 = (RTC_CRL & RTC_CRL_RSF)) == 0);
/* Wait for the last write operation to finish. */
/* TODO: Necessary? */
while ((reg32 = (RTC_CRL & RTC_CRL_RTOFF)) == 0);
}
/*---------------------------------------------------------------------------*/
/** @brief RTC Configuration on Wakeup
Enable the backup domain clocks and write access to the backup domain.
If the RTC has not been enabled, set the clock source and prescaler value.
The parameters are not used if the RTC has already been enabled.
@param[in] clock_source ::rcc_osc. RTC clock source. Only HSE, LSE
and LSI are permitted.
@param[in] prescale_val uint32_t. 20 bit prescale divider.
*/
void rtc_auto_awake(enum rcc_osc clock_source, uint32_t prescale_val)
{
uint32_t reg32;
/* Enable power and backup interface clocks. */
rcc_periph_clock_enable(RCC_PWR);
rcc_periph_clock_enable(RCC_BKP);
reg32 = rcc_rtc_clock_enabled_flag();
if (reg32 != 0) {
rtc_awake_from_standby();
} else {
rtc_awake_from_off(clock_source);
rtc_set_prescale_val(prescale_val);
}
}
/**@}*/

View File

@@ -0,0 +1,53 @@
/** @defgroup timer_file TIMER peripheral API
@ingroup peripheral_apis
@brief <b>libopencm3 STM32F1xx Timers</b>
@version 1.0.0
@date 18 August 2012
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Edward Cheeseman <evbuilder@users.sourceforge.org>
* Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/timer.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief Set 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(uint32_t timer_peripheral, enum tim_ic_id ic,
enum tim_ic_pol pol)
{
if (pol) {
TIM_CCER(timer_peripheral) |= (0x2 << (ic * 4));
} else {
TIM_CCER(timer_peripheral) &= ~(0x2 << (ic * 4));
}
}
/**@}*/

View File

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

View File

@@ -0,0 +1,31 @@
/** @defgroup crypto_file CRYPTO
*
* @ingroup STM32F2xx
*
* @brief <b>libopencm3 STM32F2xx Cryptographic controller</b>
*
* @version 1.0.0
*
* @date 14 January 2014
*
* 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/crypto.h>

View File

@@ -0,0 +1,83 @@
/** @defgroup flash_file FLASH peripheral API
*
* @ingroup peripheral_apis
*
* @brief <b>libopencm3 STM32F2xx FLASH</b>
*
* @version 1.0.0
*
* @author @htmlonly &copy; @endhtmlonly 2010
* Thomas Otto <tommi@viadmin.org>
* @author @htmlonly &copy; @endhtmlonly 2010
* Mark Butler <mbutler@physics.otago.ac.nz>
*
* @date 14 January 2014
*
* This library supports the FLASH memory controller in the STM32F2
* series of ARM Cortex Microcontrollers by ST Microelectronics.
*
* For the STM32F2xx, accessing FLASH memory is described briefly in
* section 2.3.3 of the STM32F2xx Reference Manual.
* For detailed programming information see:
* PM0059 programming manual: STM32F10xxx Flash programming
* June 2013, Doc ID DocID15687 Rev 5
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/flash.h>
void flash_wait_for_last_operation(void)
{
while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY);
}
/*---------------------------------------------------------------------------*/
/** @brief Clear the Programming Sequence Error Flag
This flag is set when incorrect programming configuration has been made.
*/
void flash_clear_pgserr_flag(void)
{
FLASH_SR |= FLASH_SR_PGSERR;
}
/*---------------------------------------------------------------------------*/
/** @brief Clear All Status Flags
Program error, end of operation, write protect error, busy.
*/
void flash_clear_status_flags(void)
{
flash_clear_pgserr_flag();
flash_clear_pgaerr_flag();
flash_clear_wrperr_flag();
flash_clear_pgperr_flag();
flash_clear_eop_flag();
}
/**@}*/

View File

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

View File

@@ -0,0 +1,444 @@
/** @defgroup rcc_file RCC peripheral API
*
* @ingroup peripheral_apis
*
* @section rcc_f2_api_ex Reset and Clock Control API.
*
* @brief <b>libopencm3 STM32F2xx Reset and Clock Control</b>
*
* @author @htmlonly &copy; @endhtmlonly 2013 Frantisek Burian <BuFran at seznam.cz>
*
* @date 18 Jun 2013
*
* This library supports the Reset and Clock Control System in the STM32 series
* of ARM Cortex Microcontrollers by ST Microelectronics.
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Federico Ruiz-Ugalde <memeruiz at gmail dot com>
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/assert.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/flash.h>
/**@{*/
/* Set the default clock frequencies after reset. */
uint32_t rcc_ahb_frequency = 16000000;
uint32_t rcc_apb1_frequency = 16000000;
uint32_t rcc_apb2_frequency = 16000000;
const struct rcc_clock_scale rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_END] = {
{ /* 120MHz */
.pllm = 8,
.plln = 240,
.pllp = 2,
.pllq = 5,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV4,
.ppre2 = RCC_CFGR_PPRE_DIV2,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_LATENCY_3WS,
.apb1_frequency = 30000000,
.apb2_frequency = 60000000,
},
};
void rcc_osc_ready_int_clear(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CIR |= RCC_CIR_PLLRDYC;
break;
case RCC_HSE:
RCC_CIR |= RCC_CIR_HSERDYC;
break;
case RCC_HSI:
RCC_CIR |= RCC_CIR_HSIRDYC;
break;
case RCC_LSE:
RCC_CIR |= RCC_CIR_LSERDYC;
break;
case RCC_LSI:
RCC_CIR |= RCC_CIR_LSIRDYC;
break;
}
}
void rcc_osc_ready_int_enable(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CIR |= RCC_CIR_PLLRDYIE;
break;
case RCC_HSE:
RCC_CIR |= RCC_CIR_HSERDYIE;
break;
case RCC_HSI:
RCC_CIR |= RCC_CIR_HSIRDYIE;
break;
case RCC_LSE:
RCC_CIR |= RCC_CIR_LSERDYIE;
break;
case RCC_LSI:
RCC_CIR |= RCC_CIR_LSIRDYIE;
break;
}
}
void rcc_osc_ready_int_disable(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CIR &= ~RCC_CIR_PLLRDYIE;
break;
case RCC_HSE:
RCC_CIR &= ~RCC_CIR_HSERDYIE;
break;
case RCC_HSI:
RCC_CIR &= ~RCC_CIR_HSIRDYIE;
break;
case RCC_LSE:
RCC_CIR &= ~RCC_CIR_LSERDYIE;
break;
case RCC_LSI:
RCC_CIR &= ~RCC_CIR_LSIRDYIE;
break;
}
}
int rcc_osc_ready_int_flag(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0);
break;
case RCC_HSE:
return ((RCC_CIR & RCC_CIR_HSERDYF) != 0);
break;
case RCC_HSI:
return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0);
break;
case RCC_LSE:
return ((RCC_CIR & RCC_CIR_LSERDYF) != 0);
break;
case RCC_LSI:
return ((RCC_CIR & RCC_CIR_LSIRDYF) != 0);
break;
}
cm3_assert_not_reached();
}
void rcc_css_int_clear(void)
{
RCC_CIR |= RCC_CIR_CSSC;
}
int rcc_css_int_flag(void)
{
return ((RCC_CIR & RCC_CIR_CSSF) != 0);
}
bool rcc_is_osc_ready(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
return RCC_CR & RCC_CR_PLLRDY;
case RCC_HSE:
return RCC_CR & RCC_CR_HSERDY;
case RCC_HSI:
return RCC_CR & RCC_CR_HSIRDY;
case RCC_LSE:
return RCC_BDCR & RCC_BDCR_LSERDY;
case RCC_LSI:
return RCC_CSR & RCC_CSR_LSIRDY;
}
return false;
}
void rcc_wait_for_osc_ready(enum rcc_osc osc)
{
while (!rcc_is_osc_ready(osc));
}
void rcc_wait_for_sysclk_status(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SWS_MASK) !=
RCC_CFGR_SWS_PLL);
break;
case RCC_HSE:
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SWS_MASK) !=
RCC_CFGR_SWS_HSE);
break;
case RCC_HSI:
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SWS_MASK) !=
RCC_CFGR_SWS_HSI);
break;
default:
/* Shouldn't be reached. */
break;
}
}
void rcc_osc_on(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CR |= RCC_CR_PLLON;
break;
case RCC_HSE:
RCC_CR |= RCC_CR_HSEON;
break;
case RCC_HSI:
RCC_CR |= RCC_CR_HSION;
break;
case RCC_LSE:
RCC_BDCR |= RCC_BDCR_LSEON;
break;
case RCC_LSI:
RCC_CSR |= RCC_CSR_LSION;
break;
}
}
void rcc_osc_off(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CR &= ~RCC_CR_PLLON;
break;
case RCC_HSE:
RCC_CR &= ~RCC_CR_HSEON;
break;
case RCC_HSI:
RCC_CR &= ~RCC_CR_HSION;
break;
case RCC_LSE:
RCC_BDCR &= ~RCC_BDCR_LSEON;
break;
case RCC_LSI:
RCC_CSR &= ~RCC_CSR_LSION;
break;
}
}
void rcc_css_enable(void)
{
RCC_CR |= RCC_CR_CSSON;
}
void rcc_css_disable(void)
{
RCC_CR &= ~RCC_CR_CSSON;
}
void rcc_set_sysclk_source(uint32_t clk)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~((1 << 1) | (1 << 0));
RCC_CFGR = (reg32 | clk);
}
void rcc_set_pll_source(uint32_t pllsrc)
{
uint32_t reg32;
reg32 = RCC_PLLCFGR;
reg32 &= ~(1 << 22);
RCC_PLLCFGR = (reg32 | (pllsrc << 22));
}
void rcc_set_ppre2(uint32_t ppre2)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~((1 << 13) | (1 << 14) | (1 << 15));
RCC_CFGR = (reg32 | (ppre2 << 13));
}
void rcc_set_ppre1(uint32_t ppre1)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~((1 << 10) | (1 << 11) | (1 << 12));
RCC_CFGR = (reg32 | (ppre1 << 10));
}
void rcc_set_hpre(uint32_t hpre)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7));
RCC_CFGR = (reg32 | (hpre << 4));
}
void rcc_set_rtcpre(uint32_t rtcpre)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~((1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20));
RCC_CFGR = (reg32 | (rtcpre << 16));
}
void rcc_set_main_pll_hsi(uint32_t pllm, uint32_t plln, uint32_t pllp,
uint32_t pllq)
{
RCC_PLLCFGR = (pllm << RCC_PLLCFGR_PLLM_SHIFT) |
(plln << RCC_PLLCFGR_PLLN_SHIFT) |
(((pllp >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT) |
(pllq << RCC_PLLCFGR_PLLQ_SHIFT);
}
void rcc_set_main_pll_hse(uint32_t pllm, uint32_t plln, uint32_t pllp,
uint32_t pllq)
{
RCC_PLLCFGR = (pllm << RCC_PLLCFGR_PLLM_SHIFT) |
(plln << RCC_PLLCFGR_PLLN_SHIFT) |
(((pllp >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT) |
RCC_PLLCFGR_PLLSRC |
(pllq << RCC_PLLCFGR_PLLQ_SHIFT);
}
uint32_t rcc_system_clock_source(void)
{
/* Return the clock source which is used as system clock. */
return (RCC_CFGR & 0x000c) >> 2;
}
void rcc_clock_setup_hse_3v3(const struct rcc_clock_scale *clock)
{
/* Enable internal high-speed oscillator. */
rcc_osc_on(RCC_HSI);
rcc_wait_for_osc_ready(RCC_HSI);
/* Select HSI as SYSCLK source. */
rcc_set_sysclk_source(RCC_CFGR_SW_HSI);
/* Enable external high-speed oscillator 8MHz. */
rcc_osc_on(RCC_HSE);
rcc_wait_for_osc_ready(RCC_HSE);
/*
* Set prescalers for AHB, ADC, APB1, APB2.
* Do this before touching the PLL (TODO: why?).
*/
rcc_set_hpre(clock->hpre);
rcc_set_ppre1(clock->ppre1);
rcc_set_ppre2(clock->ppre2);
/* Disable PLL oscillator before changing its configuration. */
rcc_osc_off(RCC_PLL);
/* Configure the PLL oscillator. */
rcc_set_main_pll_hse(clock->pllm, clock->plln,
clock->pllp, clock->pllq);
/* Enable PLL oscillator and wait for it to stabilize. */
rcc_osc_on(RCC_PLL);
rcc_wait_for_osc_ready(RCC_PLL);
/* Configure flash settings. */
flash_set_ws(clock->flash_config);
/* Select PLL as SYSCLK source. */
rcc_set_sysclk_source(RCC_CFGR_SW_PLL);
/* Wait for PLL clock to be selected. */
rcc_wait_for_sysclk_status(RCC_PLL);
/* Set the peripheral clock frequencies used. */
rcc_apb1_frequency = clock->apb1_frequency;
rcc_apb2_frequency = clock->apb2_frequency;
}
void rcc_backupdomain_reset(void)
{
/* Set the backup domain software reset. */
RCC_BDCR |= RCC_BDCR_BDRST;
/* Clear the backup domain software reset. */
RCC_BDCR &= ~RCC_BDCR_BDRST;
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the USART at base specified.
* @param usart Base address of USART to get clock frequency for.
*/
uint32_t rcc_get_usart_clk_freq(uint32_t usart)
{
if (usart == USART1_BASE || usart == USART6_BASE) {
return rcc_apb2_frequency;
} else {
return rcc_apb1_frequency;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the Timer at base specified.
* @param timer Base address of TIM to get clock frequency for.
*/
uint32_t rcc_get_timer_clk_freq(uint32_t timer)
{
/* Handle APB1 timer clocks. */
if (timer >= TIM2_BASE && timer <= TIM14_BASE) {
uint8_t ppre1 = (RCC_CFGR >> RCC_CFGR_PPRE1_SHIFT) & RCC_CFGR_PPRE1_MASK;
return (ppre1 == RCC_CFGR_PPRE_DIV_NONE) ? rcc_apb1_frequency
: 2 * rcc_apb1_frequency;
} else {
uint8_t ppre2 = (RCC_CFGR >> RCC_CFGR_PPRE2_SHIFT) & RCC_CFGR_PPRE2_MASK;
return (ppre2 == RCC_CFGR_PPRE_DIV_NONE) ? rcc_apb2_frequency
: 2 * rcc_apb2_frequency;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the I2C device at base specified.
* @param i2c Base address of I2C to get clock frequency for.
*/
uint32_t rcc_get_i2c_clk_freq(uint32_t i2c __attribute__((unused)))
{
return rcc_apb1_frequency;
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the SPI device at base specified.
* @param spi Base address of SPI device to get clock frequency for (e.g. SPI1_BASE).
*/
uint32_t rcc_get_spi_clk_freq(uint32_t spi) {
if (spi == SPI1_BASE) {
return rcc_apb2_frequency;
} else {
return rcc_apb1_frequency;
}
}
/**@}*/

View File

@@ -0,0 +1,31 @@
/* This file is used for documentation purposes. It does not need
to be compiled. All source code is in the common area.
If there is any device specific code required it can be included here,
in which case this file must be added to the compile list. */
/** @defgroup rng_file RNG
@ingroup STM32F2xx
@brief <b>libopencm3 STM32F2xx RNG</b>
*/
/*
* 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/rng.h>

View File

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

View File

@@ -0,0 +1,730 @@
/** @addtogroup adc_file ADC peripheral API
* @ingroup peripheral_apis
*
* @author @htmlonly &copy; @endhtmlonly 2012
* Ken Sarkies <ksarkies@internode.on.net>
*
* @date 30 August 2012
*
* This library supports the A/D Converter Control System in the STM32 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. The ADC resolution can be set to 12, 10, 8 or 6 bits.
*
* Each A/D converter has up to 19 channels:
* @li On ADC1 the analog channels 16 is internally connected to the
* temperature sensor, channel 17 to V<sub>REFINT</sub>, and channel 18
* to V<sub>BATT</sub>.
* @li On ADC2 and ADC3 the analog channels 16 - 18 are not used.
*
* 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_f3_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 multiple mode to
* independent.
*
* @code
* gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO1);
* rcc_periph_clock_enable(RCC_ADC1);
* adc_set_clk_prescale(RCC_CFGR_ADCPRE_BY2);
* adc_disable_scan_mode(ADC1);
* adc_set_single_conversion_mode(ADC1);
* adc_set_sample_time(ADC1, ADC_CHANNEL0, ADC_SMPR1_SMP_1DOT5CYC);
* uint8_t channels[] = ADC_CHANNEL0;
* adc_set_regular_sequence(ADC1, 1, channels);
* adc_set_multi_mode(ADC_CCR_DUAL_INDEPENDENT);
* adc_power_on(ADC1);
* adc_start_conversion_regular(ADC1);
* while (! adc_eoc(ADC1));
* reg16 = adc_read_regular(ADC1);
* @endcode
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 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/adc.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog for Regular Conversions
*
* The analog watchdog allows the monitoring of an analog signal between two
* threshold levels. The thresholds must be preset. Comparison is done before
* data alignment takes place, so the thresholds are left-aligned.
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_enable_analog_watchdog_regular(uint32_t adc)
{
ADC_CFGR1(adc) |= ADC_CFGR1_AWD1EN;
}
/*---------------------------------------------------------------------------*/
/** @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_disable_analog_watchdog_regular(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_AWD1EN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog for Injected Conversions
*
* The analog watchdog allows the monitoring of an analog signal between two
* threshold levels. The thresholds must be preset. Comparison is done before
* data alignment takes place, so the thresholds are left-aligned.
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_enable_analog_watchdog_injected(uint32_t adc)
{
ADC_CFGR1(adc) |= ADC_CFGR1_JAWD1EN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Analog Watchdog for Injected Conversions
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_disable_analog_watchdog_injected(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_JAWD1EN;
}
/*---------------------------------------------------------------------------*/
/** @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
* whole group has been converted, the next trigger will restart conversion of
* the subgroup at the beginning of the whole group.
*
* @param[in] adc ADC block register address base @ref adc_reg_base
* @param[in] length Number of channels in the group @ref adc_cr1_discnum
*/
void adc_enable_discontinuous_mode_regular(uint32_t adc, uint8_t length)
{
if ((length-1) > 7) {
return;
}
ADC_CFGR1(adc) |= ADC_CFGR1_DISCEN;
ADC_CFGR1(adc) |= ((length-1) << ADC_CFGR1_DISCNUM_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Discontinuous Mode for Regular Conversions
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_disable_discontinuous_mode_regular(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_DISCEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Discontinuous Mode for Injected Conversions
*
* In this mode the ADC converts sequentially one channel of the defined group
* of injected channels, cycling back to the first channel in the group once
* the entire group has been converted.
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_enable_discontinuous_mode_injected(uint32_t adc)
{
ADC_CFGR1(adc) |= ADC_CFGR1_JDISCEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Discontinuous Mode for Injected Conversions
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_disable_discontinuous_mode_injected(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_JDISCEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Automatic Injected Conversions
*
* The ADC converts a defined injected group of channels immediately after the
* regular channels have been converted. The external trigger on the injected
* channels is disabled as required.
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_enable_automatic_injected_group_conversion(uint32_t adc)
{
adc_disable_external_trigger_injected(adc);
ADC_CFGR1(adc) |= ADC_CFGR1_JAUTO;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Automatic Injected Conversions
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_disable_automatic_injected_group_conversion(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_JAUTO;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog for All Regular and/or Injected Channels
*
* The analog watchdog allows the monitoring of an analog signal between two
* threshold levels. The thresholds must be preset. Comparison is done before
* data alignment takes place, so the thresholds are left-aligned.
*
* @note The analog watchdog must be enabled for either or both of the regular
* or injected channels. If neither are enabled, the analog watchdog feature
* will be disabled.
*
* @ref adc_enable_analog_watchdog_injected, @ref
* adc_enable_analog_watchdog_regular.
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_enable_analog_watchdog_on_all_channels(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_AWD1SGL;
}
/*---------------------------------------------------------------------------*/
/** @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 numbe
* @ref adc_watchdog_channel
*/
void adc_enable_analog_watchdog_on_selected_channel(uint32_t adc,
uint8_t channel)
{
ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_AWD1CH) |
ADC_CFGR1_AWD1CH_VAL(channel);
ADC_CFGR1(adc) |= ADC_CFGR1_AWD1EN | ADC_CFGR1_AWD1SGL;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Injected End-Of-Conversion Interrupt
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_enable_eoc_interrupt_injected(uint32_t adc)
{
ADC_IER(adc) |= ADC_IER_JEOCIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Injected End-Of-Conversion Interrupt
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_disable_eoc_interrupt_injected(uint32_t adc)
{
ADC_IER(adc) &= ~ADC_IER_JEOCIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Injected End-Of-Sequence Interrupt
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_enable_eos_interrupt_injected(uint32_t adc)
{
ADC_IER(adc) |= ADC_IER_JEOSIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Injected End-Of-Sequence Interrupt
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_disable_eos_interrupt_injected(uint32_t adc)
{
ADC_IER(adc) &= ~ADC_IER_JEOSIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog Interrupt
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_enable_all_awd_interrupt(uint32_t adc)
{
ADC_IER(adc) |= ADC_IER_AWD1IE;
ADC_IER(adc) |= ADC_IER_AWD2IE;
ADC_IER(adc) |= ADC_IER_AWD3IE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Analog Watchdog Interrupt
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_disable_all_awd_interrupt(uint32_t adc)
{
ADC_IER(adc) &= ~ADC_IER_AWD1IE;
ADC_IER(adc) &= ~ADC_IER_AWD2IE;
ADC_IER(adc) &= ~ADC_IER_AWD3IE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Regular End-Of-Sequence Interrupt
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_enable_eos_interrupt(uint32_t adc)
{
ADC_IER(adc) |= ADC_IER_EOSIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Regular End-Of-Sequence Interrupt
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_disable_eos_interrupt(uint32_t adc)
{
ADC_IER(adc) &= ~ADC_IER_EOSIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Software Triggered Conversion on Injected Channels
*
* This starts conversion on a set of defined injected channels.
* Depending on the configuration bits JEXTEN, a conversion will start
* immediately (software trigger configuration) or once an injected hardware
* trigger event occurs (hardware trigger configuration).
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
*/
void adc_start_conversion_injected(uint32_t adc)
{
/* Start conversion on injected channels. */
ADC_CR(adc) |= ADC_CR_JADSTART;
}
/** ADC Set Analog Watchdog Upper Threshold.
* @param[in] adc ADC block register address base
* @ref adc_reg_base
* @param[in] threshold Upper threshold value
*/
void adc_set_watchdog_high_threshold(uint32_t adc, uint16_t threshold)
{
uint32_t reg32 = 0;
uint32_t mask = 0xf000ffff;
reg32 |= (threshold << 16);
reg32 &= ~mask; /* clear masked bits. */
ADC_TR1(adc) = (ADC_TR1(adc) & mask) | reg32;
ADC_TR2(adc) = (ADC_TR2(adc) & mask) | reg32;
ADC_TR3(adc) = (ADC_TR3(adc) & mask) | reg32;
}
/** ADC Set Analog Watchdog Lower Threshold.
* @param[in] adc ADC block register address base
* @ref adc_reg_base
* @param[in] threshold Lower threshold value
*/
void adc_set_watchdog_low_threshold(uint32_t adc, uint16_t threshold)
{
uint32_t reg32 = 0;
uint32_t mask = 0xfffff000;
reg32 = (uint32_t)threshold;
reg32 &= ~mask; /* clear masked bits. */
ADC_TR1(adc) = (ADC_TR1(adc) & mask) | reg32;
ADC_TR2(adc) = (ADC_TR2(adc) & mask) | reg32;
ADC_TR3(adc) = (ADC_TR3(adc) & mask) | reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set an Injected Channel Conversion Sequence
*
* Defines a sequence of channels to be converted as an injected group with a
* length from 1 to 4 channels. If this is called during conversion, the current
* conversion is reset and conversion begins again with the newly defined group.
*
* @param[in] adc Unsigned int32. ADC block register address base
* @ref adc_reg_base
* @param[in] length Unsigned int8. Number of channels in the group.
* @param[in] channel Unsigned int8[]. Set of channels in sequence, integers
* 0..18
*/
void adc_set_injected_sequence(uint32_t adc, uint8_t length, uint8_t channel[])
{
uint32_t reg32 = 0;
uint8_t i = 0;
/* Maximum sequence length is 4 channels. Minimum sequence is 1.*/
if ((length - 1) > 3) {
return;
}
for (i = 0; i < length; i++) {
reg32 |= ADC_JSQR_JSQ_VAL(4 - i, channel[length - i - 1]);
}
reg32 |= ADC_JSQR_JL_VAL(length);
ADC_JSQR(adc) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read the End-of-Conversion Flag for Injected Conversion
*
* This flag is set by hardware at the end of each injected conversion of a
* channel when a new data is available in the corresponding ADCx_JDRy register.
*
* @param[in] adc Unsigned int32. ADC block register address base
* @ref adc_reg_base
* @returns bool. End of conversion flag.
*/
bool adc_eoc_injected(uint32_t adc)
{
return ADC_ISR(adc) & ADC_ISR_JEOC;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read the End-of-Sequence Flag for Injected Conversions
*
* This flag is set after all channels of an injected group have been
* converted.
*
* @param[in] adc Unsigned int32. ADC block register address base
* @ref adc_reg_base
* @returns bool. End of conversion flag.
*/
bool adc_eos_injected(uint32_t adc)
{
return ADC_ISR(adc) & ADC_ISR_JEOS;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read from an Injected Conversion Result Register
*
* The result read back from the selected injected result register (one of four)
* is 12 bits, right or left aligned within the first 16 bits. The result can
* have a negative value if the injected channel offset has been set @see
* adc_set_injected_offset.
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
* @param[in] reg Unsigned int8. Register number (1 ... 4).
* @returns Unsigned int32 conversion result.
*/
uint32_t adc_read_injected(uint32_t adc, uint8_t reg)
{
switch (reg) {
case 1:
return ADC_JDR1(adc);
case 2:
return ADC_JDR2(adc);
case 3:
return ADC_JDR3(adc);
case 4:
return ADC_JDR4(adc);
}
return 0;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set the Injected Channel Data Offset
*
* This value is subtracted from the injected channel results after conversion
* is complete, and can result in negative results. A separate value can be
* specified for each injected data register.
*
* @param[in] adc Unsigned int32. ADC block register address base
* @ref adc_reg_base
* @param[in] reg Unsigned int8. Register number (1 ... 4).
* @param[in] offset Unsigned int32.
*/
void adc_set_injected_offset(uint32_t adc, uint8_t reg, uint32_t offset)
{
switch (reg) {
case 1:
ADC_OFR1(adc) |= ADC_OFR1_OFFSET1_EN;
ADC_OFR1(adc) |= offset;
break;
case 2:
ADC_OFR2(adc) |= ADC_OFR2_OFFSET2_EN;
ADC_OFR2(adc) |= offset;
break;
case 3:
ADC_OFR3(adc) |= ADC_OFR3_OFFSET3_EN;
ADC_OFR3(adc) |= offset;
break;
case 4:
ADC_OFR4(adc) |= ADC_OFR4_OFFSET4_EN;
ADC_OFR4(adc) |= offset;
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set Clock Prescale
*
* The ADC clock taken from the APB2 clock can be scaled down by 2, 4, 6 or 8.
*
* @param adc peripheral of choice @ref adc_reg_base
* @param[in] prescale Unsigned int32. Prescale value for ADC Clock @ref
* adc_ccr_adcpre
*/
void adc_set_clk_prescale(uint32_t adc, uint32_t prescale)
{
uint32_t reg32 = ((ADC_CCR(adc) & ~ADC_CCR_CKMODE_MASK) | prescale);
ADC_CCR(adc) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC set multi mode
*
* The multiple mode can uses these arrangement:
* - ADC1 as master and ADC2 as slave
* - ADC3 as master and ADC4 as slave
*
* This setting is applied to ADC master only (ADC1 or ADC3).
*
* The various modes possible are described in the reference manual.
*
* @param adc peripheral of choice @ref adc_reg_base
* @param[in] mode Multiple mode selection from @ref adc_multi_mode
*/
void adc_set_multi_mode(uint32_t adc, uint32_t mode)
{
ADC_CCR(adc) &= ~(ADC_CCR_DUAL_MASK << ADC_CCR_DUAL_SHIFT);
ADC_CCR(adc) |= (mode << ADC_CCR_DUAL_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable an External Trigger for Regular Channels
*
* This enables an external trigger for set of defined regular channels, and
* sets the polarity of the trigger event: rising or falling edge or both. Note
* that if the trigger polarity is zero, triggering is disabled.
*
* @param[in] adc Unsigned int32. ADC block register address base @ref
* adc_reg_base
* @param[in] trigger Unsigned int32. Trigger identifier
* @ref adc_trigger_regular
* @param[in] polarity Unsigned int32. Trigger polarity @ref
* adc_trigger_polarity_regular
*/
void adc_enable_external_trigger_regular(uint32_t adc, uint32_t trigger,
uint32_t polarity)
{
uint32_t reg32 = ADC_CFGR1(adc);
reg32 &= ~(ADC_CFGR1_EXTSEL_MASK | ADC_CFGR1_EXTEN_MASK);
reg32 |= (trigger | polarity);
ADC_CFGR1(adc) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @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(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_EXTEN_MASK;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable an External Trigger for Injected Channels
*
* This enables an external trigger for set of defined injected channels, and
* sets the polarity of the trigger event: rising or falling edge or both.
*
* @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
* @param[in] polarity Unsigned int32. Trigger polarity
* @ref adc_trigger_polarity_injected
*/
void adc_enable_external_trigger_injected(uint32_t adc, uint32_t trigger,
uint32_t polarity)
{
uint32_t reg32 = ADC_JSQR(adc);
reg32 &= ~(ADC_JSQR_JEXTSEL_MASK | ADC_JSQR_JEXTEN_MASK);
reg32 |= (trigger | polarity);
ADC_JSQR(adc) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @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(uint32_t adc)
{
ADC_JSQR(adc) &= ~ADC_JSQR_JEXTEN_MASK;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read the Analog Watchdog Flag
*
* This flag is set when the converted voltage crosses the high or low
* thresholds.
*
* @param[in] adc Unsigned int32. ADC block register address base
* @ref adc_reg_base
* @returns bool. AWD flag.
*/
bool adc_awd(uint32_t adc)
{
return (ADC_ISR(adc) & ADC_ISR_AWD1) &&
(ADC_ISR(adc) & ADC_ISR_AWD2) &&
(ADC_ISR(adc) & ADC_ISR_AWD3);
}
/**
* Enable the ADC Voltage regulator
* Before any use of the ADC, the ADC Voltage regulator must be enabled.
* You must wait up to 10uSecs afterwards before trying anything else.
* @param[in] adc ADC block register address base
* @sa adc_disable_regulator
*/
void adc_enable_regulator(uint32_t adc)
{
ADC_CR(adc) &= ~ADC_CR_ADVREGEN_MASK;
ADC_CR(adc) |= ADC_CR_ADVREGEN_ENABLE;
}
/**
* Disable the ADC Voltage regulator
* You can disable the adc vreg when not in use to save power
* @param[in] adc ADC block register address base
* @sa adc_enable_regulator
*/
void adc_disable_regulator(uint32_t adc)
{
ADC_CR(adc) &= ~ADC_CR_ADVREGEN_MASK;
ADC_CR(adc) |= ADC_CR_ADVREGEN_DISABLE;
}
/**@}*/

View File

@@ -0,0 +1,117 @@
/** @defgroup flash_file FLASH peripheral API
*
* @ingroup peripheral_apis
*
* @brief <b>libopencm3 STM32F3xx FLASH</b>
*
* @version 1.0.0
*
* @author @htmlonly &copy; @endhtmlonly 2010
* Thomas Otto <tommi@viadmin.org>
* @author @htmlonly &copy; @endhtmlonly 2010
* Mark Butler <mbutler@physics.otago.ac.nz>
*
* @date 14 January 2014
*
* This library supports the FLASH memory controller in the STM32F3
* series of ARM Cortex Microcontrollers by ST Microelectronics.
*
* For the STM32F3xx, accessing FLASH memory is described in
* section 3 of the STM32F3xx Reference Manual.
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/flash.h>
void flash_wait_for_last_operation(void)
{
while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY);
}
void flash_clear_pgerr_flag(void)
{
FLASH_SR |= FLASH_SR_PGERR;
}
void flash_clear_wrprterr_flag(void)
{
FLASH_SR |= FLASH_SR_WRPRTERR;
}
/*---------------------------------------------------------------------------*/
/** @brief Clear All Status Flags
Clears program error, end of operation, busy flags.
*/
void flash_clear_status_flags(void)
{
flash_clear_pgerr_flag();
flash_clear_wrprterr_flag();
flash_clear_eop_flag();
}
void flash_program_half_word(uint32_t address, uint16_t data)
{
flash_wait_for_last_operation();
FLASH_CR |= FLASH_CR_PG;
MMIO16(address) = data;
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_PG;
}
void flash_erase_page(uint32_t page_address)
{
flash_wait_for_last_operation();
FLASH_CR |= FLASH_CR_PER;
FLASH_AR = page_address;
FLASH_CR |= FLASH_CR_STRT;
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_PER;
}
void flash_erase_all_pages(void)
{
flash_wait_for_last_operation();
FLASH_CR |= FLASH_CR_MER;
FLASH_CR |= FLASH_CR_STRT;
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_MER;
}
/**@}*/

View File

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

View File

@@ -0,0 +1,581 @@
/** @defgroup rcc_file RCC peripheral API
*
* @ingroup peripheral_apis
*
* @brief <b>libopencm3 STM32F3xx Reset and Clock Control</b>
*
* @version 1.0.0
*
* @date 11 July 2013
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Federico Ruiz-Ugalde <memeruiz at gmail dot com>
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Modified by 2013 Fernando Cortes <fernando.corcam@gmail.com> (stm32f3)
* Modified by 2013 Guillermo Rivera <memogrg@gmail.com> (stm32f3)
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/cm3/assert.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/flash.h>
#include <libopencm3/stm32/i2c.h>
/* Set the default clock frequencies after reset. */
uint32_t rcc_ahb_frequency = 8000000;
uint32_t rcc_apb1_frequency = 8000000;
uint32_t rcc_apb2_frequency = 8000000;
const struct rcc_clock_scale rcc_hsi_configs[] = {
{ /* 48MHz */
.pllmul = RCC_CFGR_PLLMUL_MUL12,
.pllsrc = RCC_CFGR_PLLSRC_HSI_DIV2,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.flash_waitstates = 1,
.ahb_frequency = 48000000,
.apb1_frequency = 24000000,
.apb2_frequency = 48000000,
},
{ /* 64MHz */
.pllmul = RCC_CFGR_PLLMUL_MUL16,
.pllsrc = RCC_CFGR_PLLSRC_HSI_DIV2,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.flash_waitstates = 2,
.ahb_frequency = 64000000,
.apb1_frequency = 32000000,
.apb2_frequency = 64000000,
}
};
const struct rcc_clock_scale rcc_hse8mhz_configs[] = {
{
.pllsrc = RCC_CFGR_PLLSRC_HSE_PREDIV,
.pllmul = RCC_CFGR_PLLMUL_MUL9,
.plldiv = RCC_CFGR2_PREDIV_NODIV,
.usbdiv1 = false,
.flash_waitstates = 2,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.ahb_frequency = 72e6,
.apb1_frequency = 36e6,
.apb2_frequency = 72e6,
}
};
void rcc_osc_ready_int_clear(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CIR |= RCC_CIR_PLLRDYC;
break;
case RCC_HSE:
RCC_CIR |= RCC_CIR_HSERDYC;
break;
case RCC_HSI:
RCC_CIR |= RCC_CIR_HSIRDYC;
break;
case RCC_LSE:
RCC_CIR |= RCC_CIR_LSERDYC;
break;
case RCC_LSI:
RCC_CIR |= RCC_CIR_LSIRDYC;
break;
}
}
void rcc_osc_ready_int_enable(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CIR |= RCC_CIR_PLLRDYIE;
break;
case RCC_HSE:
RCC_CIR |= RCC_CIR_HSERDYIE;
break;
case RCC_HSI:
RCC_CIR |= RCC_CIR_HSIRDYIE;
break;
case RCC_LSE:
RCC_CIR |= RCC_CIR_LSERDYIE;
break;
case RCC_LSI:
RCC_CIR |= RCC_CIR_LSIRDYIE;
break;
}
}
void rcc_osc_ready_int_disable(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CIR &= ~RCC_CIR_PLLRDYIE;
break;
case RCC_HSE:
RCC_CIR &= ~RCC_CIR_HSERDYIE;
break;
case RCC_HSI:
RCC_CIR &= ~RCC_CIR_HSIRDYIE;
break;
case RCC_LSE:
RCC_CIR &= ~RCC_CIR_LSERDYIE;
break;
case RCC_LSI:
RCC_CIR &= ~RCC_CIR_LSIRDYIE;
break;
}
}
int rcc_osc_ready_int_flag(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0);
break;
case RCC_HSE:
return ((RCC_CIR & RCC_CIR_HSERDYF) != 0);
break;
case RCC_HSI:
return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0);
break;
case RCC_LSE:
return ((RCC_CIR & RCC_CIR_LSERDYF) != 0);
break;
case RCC_LSI:
return ((RCC_CIR & RCC_CIR_LSIRDYF) != 0);
break;
}
cm3_assert_not_reached();
}
void rcc_css_int_clear(void)
{
RCC_CIR |= RCC_CIR_CSSC;
}
int rcc_css_int_flag(void)
{
return ((RCC_CIR & RCC_CIR_CSSF) != 0);
}
bool rcc_is_osc_ready(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
return RCC_CR & RCC_CR_PLLRDY;
case RCC_HSE:
return RCC_CR & RCC_CR_HSERDY;
case RCC_HSI:
return RCC_CR & RCC_CR_HSIRDY;
case RCC_LSE:
return RCC_BDCR & RCC_BDCR_LSERDY;
case RCC_LSI:
return RCC_CSR & RCC_CSR_LSIRDY;
}
return false;
}
void rcc_wait_for_osc_ready(enum rcc_osc osc)
{
while (!rcc_is_osc_ready(osc));
}
void rcc_wait_for_osc_not_ready(enum rcc_osc osc)
{
while (rcc_is_osc_ready(osc));
}
void rcc_wait_for_sysclk_status(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SWS_MASK) !=
RCC_CFGR_SWS_PLL);
break;
case RCC_HSE:
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SWS_MASK) !=
RCC_CFGR_SWS_HSE);
break;
case RCC_HSI:
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SWS_MASK) !=
RCC_CFGR_SWS_HSI);
break;
default:
/* Shouldn't be reached. */
break;
}
}
void rcc_osc_on(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CR |= RCC_CR_PLLON;
break;
case RCC_HSE:
RCC_CR |= RCC_CR_HSEON;
break;
case RCC_HSI:
RCC_CR |= RCC_CR_HSION;
break;
case RCC_LSE:
RCC_BDCR |= RCC_BDCR_LSEON;
break;
case RCC_LSI:
RCC_CSR |= RCC_CSR_LSION;
break;
}
}
void rcc_osc_off(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CR &= ~RCC_CR_PLLON;
break;
case RCC_HSE:
RCC_CR &= ~RCC_CR_HSEON;
break;
case RCC_HSI:
RCC_CR &= ~RCC_CR_HSION;
break;
case RCC_LSE:
RCC_BDCR &= ~RCC_BDCR_LSEON;
break;
case RCC_LSI:
RCC_CSR &= ~RCC_CSR_LSION;
break;
}
}
void rcc_css_enable(void)
{
RCC_CR |= RCC_CR_CSSON;
}
void rcc_css_disable(void)
{
RCC_CR &= ~RCC_CR_CSSON;
}
void rcc_set_sysclk_source(uint32_t clk)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~((1 << 1) | (1 << 0));
RCC_CFGR = (reg32 | clk);
}
void rcc_set_pll_source(uint32_t pllsrc)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~RCC_CFGR_PLLSRC;
RCC_CFGR = (reg32 | (pllsrc << 16));
}
void rcc_set_ppre2(uint32_t ppre2)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~(RCC_CFGR_PPRE2_MASK << RCC_CFGR_PPRE2_SHIFT);
RCC_CFGR = (reg32 | (ppre2 << RCC_CFGR_PPRE2_SHIFT));
}
void rcc_set_ppre1(uint32_t ppre1)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~(RCC_CFGR_PPRE1_MASK << RCC_CFGR_PPRE1_SHIFT);
RCC_CFGR = (reg32 | (ppre1 << RCC_CFGR_PPRE1_SHIFT));
}
void rcc_set_hpre(uint32_t hpre)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~(RCC_CFGR_HPRE_MASK << RCC_CFGR_HPRE_SHIFT);
RCC_CFGR = (reg32 | (hpre << RCC_CFGR_HPRE_SHIFT));
}
/**
* Set PLL Source pre-divider **CAUTION**.
* On some F3 devices, prediv only applies to HSE source. On others,
* this is _after_ source selection. See also f0.
* @param[in] prediv division by prediv+1 @ref rcc_cfgr2_prediv
*/
void rcc_set_prediv(uint32_t prediv)
{
RCC_CFGR2 = (RCC_CFGR2 & ~RCC_CFGR2_PREDIV) | prediv;
}
void rcc_set_pll_multiplier(uint32_t pll)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~(RCC_CFGR_PLLMUL_MASK << RCC_CFGR_PLLMUL_SHIFT);
RCC_CFGR = (reg32 | (pll << RCC_CFGR_PLLMUL_SHIFT));
}
uint32_t rcc_get_system_clock_source(void)
{
/* Return the clock source which is used as system clock. */
return (RCC_CFGR & 0x000c) >> 2;
}
/**
* Setup clocks to run from PLL.
* The arguments provide the pll source, multipliers, dividers, all that's
* needed to establish a system clock.
* @param clock clock information structure
*/
void rcc_clock_setup_pll(const struct rcc_clock_scale *clock)
{
if (clock->pllsrc == RCC_CFGR_PLLSRC_HSE_PREDIV) {
rcc_osc_on(RCC_HSE);
rcc_wait_for_osc_ready(RCC_HSE);
} else {
rcc_osc_on(RCC_HSI);
rcc_wait_for_osc_ready(RCC_HSI);
}
rcc_osc_off(RCC_PLL);
rcc_usb_prescale_1_5();
if (clock->usbdiv1) {
rcc_usb_prescale_1();
}
rcc_wait_for_osc_not_ready(RCC_PLL);
rcc_set_pll_source(clock->pllsrc);
rcc_set_pll_multiplier(clock->pllmul);
rcc_set_prediv(clock->plldiv);
/* Enable PLL oscillator and wait for it to stabilize. */
rcc_osc_on(RCC_PLL);
rcc_wait_for_osc_ready(RCC_PLL);
/* Configure flash settings. */
flash_prefetch_enable();
flash_set_ws(clock->flash_waitstates);
rcc_set_hpre(clock->hpre);
rcc_set_ppre2(clock->ppre2);
rcc_set_ppre1(clock->ppre1);
/* Select PLL as SYSCLK source. */
rcc_set_sysclk_source(RCC_CFGR_SW_PLL);
/* Wait for PLL clock to be selected. */
rcc_wait_for_sysclk_status(RCC_PLL);
/* Set the peripheral clock frequencies used. */
rcc_ahb_frequency = clock->ahb_frequency;
rcc_apb1_frequency = clock->apb1_frequency;
rcc_apb2_frequency = clock->apb2_frequency;
}
void __attribute__((deprecated)) rcc_clock_setup_hsi(const struct rcc_clock_scale *clock)
{
/* Enable internal high-speed oscillator. */
rcc_osc_on(RCC_HSI);
rcc_wait_for_osc_ready(RCC_HSI);
/* Select HSI as SYSCLK source. */
rcc_set_sysclk_source(RCC_CFGR_SW_HSI); /* XXX: se cayo */
rcc_wait_for_sysclk_status(RCC_HSI);
rcc_osc_off(RCC_PLL);
rcc_wait_for_osc_not_ready(RCC_PLL);
rcc_set_pll_source(clock->pllsrc);
rcc_set_pll_multiplier(clock->pllmul);
/* Enable PLL oscillator and wait for it to stabilize. */
rcc_osc_on(RCC_PLL);
rcc_wait_for_osc_ready(RCC_PLL);
/*
* Set prescalers for AHB, ADC, APB1, APB2.
* Do this before touching the PLL (TODO: why?).
*/
rcc_set_hpre(clock->hpre);
rcc_set_ppre2(clock->ppre2);
rcc_set_ppre1(clock->ppre1);
/* Configure flash settings. */
flash_set_ws(clock->flash_waitstates);
/* Select PLL as SYSCLK source. */
rcc_set_sysclk_source(RCC_CFGR_SW_PLL); /* XXX: se cayo */
/* Wait for PLL clock to be selected. */
rcc_wait_for_sysclk_status(RCC_PLL);
/* Set the peripheral clock frequencies used. */
rcc_ahb_frequency = clock->ahb_frequency;
rcc_apb1_frequency = clock->apb1_frequency;
rcc_apb2_frequency = clock->apb2_frequency;
}
void rcc_backupdomain_reset(void)
{
/* Set the backup domain software reset. */
RCC_BDCR |= RCC_BDCR_BDRST;
/* Clear the backup domain software reset. */
RCC_BDCR &= ~RCC_BDCR_BDRST;
}
void rcc_set_i2c_clock_hsi(uint32_t i2c)
{
if (i2c == I2C1) {
RCC_CFGR3 &= ~RCC_CFGR3_I2C1SW;
}
if (i2c == I2C2) {
RCC_CFGR3 &= ~RCC_CFGR3_I2C2SW;
}
}
void rcc_set_i2c_clock_sysclk(uint32_t i2c)
{
if (i2c == I2C1) {
RCC_CFGR3 |= RCC_CFGR3_I2C1SW;
}
if (i2c == I2C2) {
RCC_CFGR3 |= RCC_CFGR3_I2C2SW;
}
}
uint32_t rcc_get_i2c_clocks(void)
{
return RCC_CFGR3 & (RCC_CFGR3_I2C1SW | RCC_CFGR3_I2C2SW);
}
void rcc_usb_prescale_1_5(void)
{
RCC_CFGR &= ~RCC_CFGR_USBPRES;
}
void rcc_usb_prescale_1(void)
{
RCC_CFGR |= RCC_CFGR_USBPRES;
}
void rcc_adc_prescale(uint32_t prescale1, uint32_t prescale2)
{
uint32_t clear_mask = (RCC_CFGR2_ADCxPRES_MASK
<< RCC_CFGR2_ADC12PRES_SHIFT)
| (RCC_CFGR2_ADCxPRES_MASK
<< RCC_CFGR2_ADC34PRES_SHIFT);
uint32_t set = (prescale1 << RCC_CFGR2_ADC12PRES_SHIFT) |
(prescale2 << RCC_CFGR2_ADC34PRES_SHIFT);
RCC_CFGR2 &= ~(clear_mask);
RCC_CFGR2 |= (set);
}
static uint32_t rcc_get_usart_clksel_freq(uint32_t apb_clk, uint8_t shift) {
uint8_t clksel = (RCC_CFGR3 >> shift) & RCC_CFGR3_UARTxSW_MASK;
uint8_t hpre = (RCC_CFGR >> RCC_CFGR_HPRE_SHIFT) & RCC_CFGR_HPRE_MASK;
switch (clksel) {
case RCC_CFGR3_UARTxSW_PCLK:
return apb_clk;
case RCC_CFGR3_UARTxSW_SYSCLK:
return rcc_ahb_frequency * rcc_get_div_from_hpre(hpre);
case RCC_CFGR3_UARTxSW_LSE:
return 32768;
case RCC_CFGR3_UARTxSW_HSI:
return 8000000U;
}
cm3_assert_not_reached();
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the USART at base specified.
* @param usart Base address of USART to get clock frequency for.
*/
uint32_t rcc_get_usart_clk_freq(uint32_t usart)
{
/* Handle values with selectable clocks. */
if (usart == USART1_BASE) {
return rcc_get_usart_clksel_freq(rcc_apb2_frequency, RCC_CFGR3_UART1SW_SHIFT);
} else if (usart == USART2_BASE) {
return rcc_get_usart_clksel_freq(rcc_apb1_frequency, RCC_CFGR3_UART2SW_SHIFT);
} else if (usart == USART3_BASE) {
return rcc_get_usart_clksel_freq(rcc_apb1_frequency, RCC_CFGR3_UART3SW_SHIFT);
} else if (usart == UART4_BASE) {
return rcc_get_usart_clksel_freq(rcc_apb1_frequency, RCC_CFGR3_UART4SW_SHIFT);
} else { /* UART5 */
return rcc_get_usart_clksel_freq(rcc_apb1_frequency, RCC_CFGR3_UART5SW_SHIFT);
}
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the Timer at base specified.
* @param timer Base address of TIM to get clock frequency for.
*/
uint32_t rcc_get_timer_clk_freq(uint32_t timer)
{
/* Handle APB1 timer clocks. */
if (timer >= TIM2_BASE && timer <= TIM7_BASE) {
uint8_t ppre1 = (RCC_CFGR >> RCC_CFGR_PPRE1_SHIFT) & RCC_CFGR_PPRE1_MASK;
return (ppre1 == RCC_CFGR_PPRE1_DIV_NONE) ? rcc_apb1_frequency
: 2 * rcc_apb1_frequency;
} else {
uint8_t ppre2 = (RCC_CFGR >> RCC_CFGR_PPRE2_SHIFT) & RCC_CFGR_PPRE2_MASK;
return (ppre2 == RCC_CFGR_PPRE2_DIV_NONE) ? rcc_apb2_frequency
: 2 * rcc_apb2_frequency;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the I2C device at base specified.
* @param i2c Base address of I2C to get clock frequency for.
*/
uint32_t rcc_get_i2c_clk_freq(uint32_t i2c)
{
if (i2c == I2C1_BASE) {
if (RCC_CFGR3 & RCC_CFGR3_I2C1SW) {
uint8_t hpre = (RCC_CFGR >> RCC_CFGR_HPRE_SHIFT) & RCC_CFGR_HPRE_MASK;
return rcc_ahb_frequency * rcc_get_div_from_hpre(hpre);
} else {
return 8000000U;
}
} else {
return rcc_apb1_frequency;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the SPI device at base specified.
* @param spi Base address of SPI device to get clock frequency for (e.g. SPI1_BASE).
*/
uint32_t rcc_get_spi_clk_freq(uint32_t spi) {
if (spi == SPI1_BASE || spi == SPI4_BASE) {
return rcc_apb2_frequency;
} else {
return rcc_apb1_frequency;
}
}
/**@}*/

View File

@@ -0,0 +1,27 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
* Copyright (C) 2011 Fergus Noble <fergusnoble@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/scb.h>
static void pre_main(void)
{
/* Enable access to Floating-Point coprocessor. */
SCB_CPACR |= SCB_CPACR_FULL * (SCB_CPACR_CP10 | SCB_CPACR_CP11);
}

View File

@@ -0,0 +1,79 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
LIBNAME = libopencm3_stm32f4
SRCLIBDIR ?= ../..
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-Wall -Wextra -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../../include -fno-common \
-mcpu=cortex-m4 -mthumb $(FP_FLAGS) \
-Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DSTM32F4
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += adc_common_v1.o adc_common_v1_multi.o adc_common_f47.o
OBJS += can.o
OBJS += crc_common_all.o
OBJS += crypto_common_f24.o crypto.o
OBJS += dac_common_all.o dac_common_v1.o
OBJS += dcmi_common_f47.o
OBJS += desig_common_all.o desig_common_v1.o
OBJS += dma_common_f24.o
OBJS += dma2d_common_f47.o
OBJS += dsi_common_f47.o
OBJS += exti_common_all.o
OBJS += flash.o flash_common_all.o flash_common_f.o flash_common_f24.o
OBJS += flash_common_idcache.o
OBJS += fmc_common_f47.o
OBJS += gpio_common_all.o gpio_common_f0234.o
OBJS += hash_common_f24.o
OBJS += i2c_common_v1.o
OBJS += iwdg_common_all.o
OBJS += lptimer_common_all.o
OBJS += ltdc_common_f47.o
OBJS += pwr_common_v1.o pwr.o
OBJS += rcc_common_all.o rcc.o
OBJS += rng_common_v1.o
OBJS += rtc_common_l1f024.o rtc.o
OBJS += spi_common_all.o spi_common_v1.o spi_common_v1_frf.o
OBJS += timer_common_all.o timer_common_f0234.o timer_common_f24.o
OBJS += usart_common_all.o usart_common_f124.o
OBJS += quadspi_common_v1.o
OBJS += usb.o usb_standard.o usb_control.o usb_msc.o
OBJS += usb_hid.o
OBJS += usb_audio.o usb_cdc.o usb_midi.o
OBJS += usb_dwc_common.o usb_f107.o usb_f207.o
OBJS += mac.o phy.o mac_stm32fxx7.o phy_ksz80x1.o
VPATH += ../../usb:../:../../cm3:../common
VPATH += ../../ethernet
include ../../Makefile.include

View File

@@ -0,0 +1,66 @@
/** @defgroup crypto_file CRYPTO
*
* @ingroup STM32F4xx
*
* @brief <b>libopencm3 STM32F4xx CRYPTO</b>
*
* @version 1.0.0
*
* @date 18 Jun 2013
*
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/crypto.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief Set the MAC algorithm
*/
void crypto_set_mac_algorithm(enum crypto_mode_mac mode)
{
crypto_set_algorithm((enum crypto_mode) mode);
}
/**
* @brief Swap context
*
*@param[in] buf uint32_t Memory space for swap (16 items length)
*/
void crypto_context_swap(uint32_t *buf)
{
int i;
/* Apply exact order of ? */
for (i = 0; i < 8; i++) {
uint32_t save = *buf;
*buf++ = CRYP_CSGCMCCMR(i);
CRYP_CSGCMCCMR(i) = save;
};
for (i = 0; i < 8; i++) {
uint32_t save = *buf;
*buf++ = CRYP_CSGCMR(i);
CRYP_CSGCMCCMR(i) = save;
};
}
/**@}*/

View File

@@ -0,0 +1,83 @@
/** @defgroup flash_file FLASH peripheral API
*
* @ingroup peripheral_apis
*
* @brief <b>libopencm3 STM32F4xx FLASH</b>
*
* @version 1.0.0
*
* @author @htmlonly &copy; @endhtmlonly 2010
* Thomas Otto <tommi@viadmin.org>
* @author @htmlonly &copy; @endhtmlonly 2010
* Mark Butler <mbutler@physics.otago.ac.nz>
*
* @date 14 January 2014
*
* This library supports the FLASH memory controller in the STM32F4
* series of ARM Cortex Microcontrollers by ST Microelectronics.
*
* For the STM32F4xx, accessing FLASH memory is described briefly in
* section 2.3.3 of the STM32F4xx Reference Manual.
* For detailed programming information see:
* PM0081 programming manual: STM32F10xxx Flash programming
* September 2011, Doc ID 018520 Rev 1
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/flash.h>
void flash_wait_for_last_operation(void)
{
while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY);
}
/*---------------------------------------------------------------------------*/
/** @brief Clear the Programming Sequence Error Flag
This flag is set when incorrect programming configuration has been made.
*/
void flash_clear_pgserr_flag(void)
{
FLASH_SR |= FLASH_SR_PGSERR;
}
/*---------------------------------------------------------------------------*/
/** @brief Clear All Status Flags
Program error, end of operation, write protect error, busy.
*/
void flash_clear_status_flags(void)
{
flash_clear_pgserr_flag();
flash_clear_pgaerr_flag();
flash_clear_wrperr_flag();
flash_clear_pgperr_flag();
flash_clear_eop_flag();
}
/**@}*/

View File

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

View File

@@ -0,0 +1,49 @@
/** @defgroup pwr_file PWR peripheral API
*
* @ingroup peripheral_apis
*
* @brief <b>libopencm3 STM32F4xx Power Control</b>
*
* @version 1.0.0
*
* @author @htmlonly &copy; @endhtmlonly 2011 Stephen Caudle <scaudle@doceme.com>
*
* @date 4 March 2013
*
* This library supports the power control system for the
* STM32F4 series of ARM Cortex Microcontrollers by ST Microelectronics.
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/pwr.h>
/**@{*/
void pwr_set_vos_scale(enum pwr_vos_scale scale)
{
uint32_t reg32;
reg32 = PWR_CR & ~(PWR_CR_VOS_MASK << PWR_CR_VOS_SHIFT);
reg32 |= (scale & PWR_CR_VOS_MASK) << PWR_CR_VOS_SHIFT;
PWR_CR = reg32;
}
/**@}*/

View File

@@ -0,0 +1,926 @@
/** @defgroup rcc_file RCC peripheral API
*
* @ingroup peripheral_apis
*
* @section rcc_f4_api_ex Reset and Clock Control API.
*
* @brief <b>libopencm3 STM32F4xx Reset and Clock Control</b>
*
* @author @htmlonly &copy; @endhtmlonly 2013 Frantisek Burian <BuFran at seznam.cz>
*
* @date 18 Jun 2013
*
* This library supports the Reset and Clock Control System in the STM32 series
* of ARM Cortex Microcontrollers by ST Microelectronics.
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Federico Ruiz-Ugalde <memeruiz at gmail dot com>
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/assert.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/pwr.h>
#include <libopencm3/stm32/flash.h>
/**@{*/
/* Set the default clock frequencies after reset. */
uint32_t rcc_ahb_frequency = 16000000;
uint32_t rcc_apb1_frequency = 16000000;
uint32_t rcc_apb2_frequency = 16000000;
const struct rcc_clock_scale rcc_hsi_configs[RCC_CLOCK_3V3_END] = {
{ /* 84MHz */
.pllm = 16,
.plln = 336,
.pllp = 4,
.pllq = 7,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSI_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_LATENCY_2WS,
.ahb_frequency = 84000000,
.apb1_frequency = 42000000,
.apb2_frequency = 84000000,
},
{ /* 96MHz */
.pllm = 8,
.plln = 96,
.pllp = 2,
.pllq = 4,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSI_CLK,
.hpre = RCC_CFGR_HPRE_DIV_NONE,
.ppre1 = RCC_CFGR_PPRE_DIV_2,
.ppre2 = RCC_CFGR_PPRE_DIV_NONE,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_3WS,
.ahb_frequency = 96000000,
.apb1_frequency = 48000000,
.apb2_frequency = 96000000
},
{ /* 168MHz */
.pllm = 16,
.plln = 336,
.pllp = 2,
.pllq = 7,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSI_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV4,
.ppre2 = RCC_CFGR_PPRE_DIV2,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_LATENCY_5WS,
.ahb_frequency = 168000000,
.apb1_frequency = 42000000,
.apb2_frequency = 84000000,
},
{ /* 180MHz */
.pllm = 16,
.plln = 360,
.pllp = 2,
.pllq = 8,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSI_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV4,
.ppre2 = RCC_CFGR_PPRE_DIV2,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_LATENCY_5WS,
.ahb_frequency = 180000000,
.apb1_frequency = 45000000,
.apb2_frequency = 90000000,
},
};
const struct rcc_clock_scale rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_END] = {
{ /* 84MHz */
.pllm = 8,
.plln = 336,
.pllp = 4,
.pllq = 7,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_LATENCY_2WS,
.ahb_frequency = 84000000,
.apb1_frequency = 42000000,
.apb2_frequency = 84000000,
},
{ /* 96MHz */
.pllm = 4,
.plln = 96,
.pllp = 2,
.pllq = 4,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_DIV_NONE,
.ppre1 = RCC_CFGR_PPRE_DIV_2,
.ppre2 = RCC_CFGR_PPRE_DIV_NONE,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_3WS,
.ahb_frequency = 96000000,
.apb1_frequency = 48000000,
.apb2_frequency = 96000000
},
{ /* 168MHz */
.pllm = 8,
.plln = 336,
.pllp = 2,
.pllq = 7,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV4,
.ppre2 = RCC_CFGR_PPRE_DIV2,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_LATENCY_5WS,
.ahb_frequency = 168000000,
.apb1_frequency = 42000000,
.apb2_frequency = 84000000,
},
{ /* 180MHz */
.pllm = 8,
.plln = 360,
.pllp = 2,
.pllq = 8,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV4,
.ppre2 = RCC_CFGR_PPRE_DIV2,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_LATENCY_5WS,
.ahb_frequency = 180000000,
.apb1_frequency = 45000000,
.apb2_frequency = 90000000,
},
};
const struct rcc_clock_scale rcc_hse_12mhz_3v3[RCC_CLOCK_3V3_END] = {
{ /* 84MHz */
.pllm = 12,
.plln = 336,
.pllp = 4,
.pllq = 7,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_LATENCY_2WS,
.ahb_frequency = 84000000,
.apb1_frequency = 42000000,
.apb2_frequency = 84000000,
},
{ /* 96MHz */
.pllm = 6,
.plln = 96,
.pllp = 2,
.pllq = 4,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_DIV_NONE,
.ppre1 = RCC_CFGR_PPRE_DIV_2,
.ppre2 = RCC_CFGR_PPRE_DIV_NONE,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_3WS,
.ahb_frequency = 96000000,
.apb1_frequency = 48000000,
.apb2_frequency = 96000000
},
{ /* 168MHz */
.pllm = 12,
.plln = 336,
.pllp = 2,
.pllq = 7,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV4,
.ppre2 = RCC_CFGR_PPRE_DIV2,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_LATENCY_5WS,
.ahb_frequency = 168000000,
.apb1_frequency = 42000000,
.apb2_frequency = 84000000,
},
{ /* 180MHz */
.pllm = 12,
.plln = 360,
.pllp = 2,
.pllq = 8,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV4,
.ppre2 = RCC_CFGR_PPRE_DIV2,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_LATENCY_5WS,
.ahb_frequency = 180000000,
.apb1_frequency = 45000000,
.apb2_frequency = 90000000,
},
};
const struct rcc_clock_scale rcc_hse_16mhz_3v3[RCC_CLOCK_3V3_END] = {
{ /* 84MHz */
.pllm = 16,
.plln = 336,
.pllp = 4,
.pllq = 7,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_LATENCY_2WS,
.ahb_frequency = 84000000,
.apb1_frequency = 42000000,
.apb2_frequency = 84000000,
},
{ /* 96MHz */
.pllm = 8,
.plln = 96,
.pllp = 2,
.pllq = 4,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_DIV_NONE,
.ppre1 = RCC_CFGR_PPRE_DIV_2,
.ppre2 = RCC_CFGR_PPRE_DIV_NONE,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_3WS,
.ahb_frequency = 96000000,
.apb1_frequency = 48000000,
.apb2_frequency = 96000000
},
{ /* 168MHz */
.pllm = 16,
.plln = 336,
.pllp = 2,
.pllq = 7,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV4,
.ppre2 = RCC_CFGR_PPRE_DIV2,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_LATENCY_5WS,
.ahb_frequency = 168000000,
.apb1_frequency = 42000000,
.apb2_frequency = 84000000,
},
{ /* 180MHz */
.pllm = 16,
.plln = 360,
.pllp = 2,
.pllq = 8,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV4,
.ppre2 = RCC_CFGR_PPRE_DIV2,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_LATENCY_5WS,
.ahb_frequency = 180000000,
.apb1_frequency = 45000000,
.apb2_frequency = 90000000,
},
};
const struct rcc_clock_scale rcc_hse_25mhz_3v3[RCC_CLOCK_3V3_END] = {
{ /* 84MHz */
.pllm = 25,
.plln = 336,
.pllp = 4,
.pllq = 7,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_LATENCY_2WS,
.ahb_frequency = 84000000,
.apb1_frequency = 42000000,
.apb2_frequency = 84000000,
},
{ /* 96MHz */
.pllm = 25,
.plln = 192,
.pllp = 2,
.pllq = 4,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_DIV_NONE,
.ppre1 = RCC_CFGR_PPRE_DIV_2,
.ppre2 = RCC_CFGR_PPRE_DIV_NONE,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_3WS,
.ahb_frequency = 96000000,
.apb1_frequency = 48000000,
.apb2_frequency = 96000000
},
{ /* 168MHz */
.pllm = 25,
.plln = 336,
.pllp = 2,
.pllq = 7,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV4,
.ppre2 = RCC_CFGR_PPRE_DIV2,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_LATENCY_5WS,
.ahb_frequency = 168000000,
.apb1_frequency = 42000000,
.apb2_frequency = 84000000,
},
{ /* 180MHz */
.pllm = 25,
.plln = 360,
.pllp = 2,
.pllq = 8,
.pllr = 0,
.pll_source = RCC_CFGR_PLLSRC_HSE_CLK,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV4,
.ppre2 = RCC_CFGR_PPRE_DIV2,
.voltage_scale = PWR_SCALE1,
.flash_config = FLASH_ACR_DCEN | FLASH_ACR_ICEN |
FLASH_ACR_LATENCY_5WS,
.ahb_frequency = 180000000,
.apb1_frequency = 45000000,
.apb2_frequency = 90000000,
},
};
void rcc_osc_ready_int_clear(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CIR |= RCC_CIR_PLLRDYC;
break;
case RCC_HSE:
RCC_CIR |= RCC_CIR_HSERDYC;
break;
case RCC_HSI:
RCC_CIR |= RCC_CIR_HSIRDYC;
break;
case RCC_LSE:
RCC_CIR |= RCC_CIR_LSERDYC;
break;
case RCC_LSI:
RCC_CIR |= RCC_CIR_LSIRDYC;
break;
case RCC_PLLSAI:
RCC_CIR |= RCC_CIR_PLLSAIRDYC;
break;
case RCC_PLLI2S:
RCC_CIR |= RCC_CIR_PLLI2SRDYC;
break;
}
}
void rcc_osc_ready_int_enable(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CIR |= RCC_CIR_PLLRDYIE;
break;
case RCC_HSE:
RCC_CIR |= RCC_CIR_HSERDYIE;
break;
case RCC_HSI:
RCC_CIR |= RCC_CIR_HSIRDYIE;
break;
case RCC_LSE:
RCC_CIR |= RCC_CIR_LSERDYIE;
break;
case RCC_LSI:
RCC_CIR |= RCC_CIR_LSIRDYIE;
break;
case RCC_PLLSAI:
RCC_CIR |= RCC_CIR_PLLSAIRDYIE;
break;
case RCC_PLLI2S:
RCC_CIR |= RCC_CIR_PLLI2SRDYIE;
break;
}
}
void rcc_osc_ready_int_disable(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CIR &= ~RCC_CIR_PLLRDYIE;
break;
case RCC_HSE:
RCC_CIR &= ~RCC_CIR_HSERDYIE;
break;
case RCC_HSI:
RCC_CIR &= ~RCC_CIR_HSIRDYIE;
break;
case RCC_LSE:
RCC_CIR &= ~RCC_CIR_LSERDYIE;
break;
case RCC_LSI:
RCC_CIR &= ~RCC_CIR_LSIRDYIE;
break;
case RCC_PLLSAI:
RCC_CIR &= ~RCC_CIR_PLLSAIRDYIE;
break;
case RCC_PLLI2S:
RCC_CIR &= ~RCC_CIR_PLLI2SRDYIE;
break;
}
}
int rcc_osc_ready_int_flag(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0);
case RCC_HSE:
return ((RCC_CIR & RCC_CIR_HSERDYF) != 0);
case RCC_HSI:
return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0);
case RCC_LSE:
return ((RCC_CIR & RCC_CIR_LSERDYF) != 0);
case RCC_LSI:
return ((RCC_CIR & RCC_CIR_LSIRDYF) != 0);
case RCC_PLLSAI:
return ((RCC_CIR & RCC_CIR_PLLSAIRDYF) != 0);
case RCC_PLLI2S:
return ((RCC_CIR & RCC_CIR_PLLI2SRDYF) != 0);
}
return 0;
}
void rcc_css_int_clear(void)
{
RCC_CIR |= RCC_CIR_CSSC;
}
int rcc_css_int_flag(void)
{
return ((RCC_CIR & RCC_CIR_CSSF) != 0);
}
bool rcc_is_osc_ready(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
return RCC_CR & RCC_CR_PLLRDY;
case RCC_HSE:
return RCC_CR & RCC_CR_HSERDY;
case RCC_HSI:
return RCC_CR & RCC_CR_HSIRDY;
case RCC_LSE:
return RCC_BDCR & RCC_BDCR_LSERDY;
case RCC_LSI:
return RCC_CSR & RCC_CSR_LSIRDY;
case RCC_PLLSAI:
return RCC_CR & RCC_CR_PLLSAIRDY;
case RCC_PLLI2S:
return RCC_CR & RCC_CR_PLLI2SRDY;
}
return false;
}
void rcc_wait_for_osc_ready(enum rcc_osc osc)
{
while (!rcc_is_osc_ready(osc));
}
void rcc_wait_for_sysclk_status(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SWS_MASK) !=
RCC_CFGR_SWS_PLL);
break;
case RCC_HSE:
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SWS_MASK) !=
RCC_CFGR_SWS_HSE);
break;
case RCC_HSI:
while (((RCC_CFGR >> RCC_CFGR_SWS_SHIFT) & RCC_CFGR_SWS_MASK) !=
RCC_CFGR_SWS_HSI);
break;
default:
/* Shouldn't be reached. */
break;
}
}
void rcc_osc_on(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CR |= RCC_CR_PLLON;
break;
case RCC_HSE:
RCC_CR |= RCC_CR_HSEON;
break;
case RCC_HSI:
RCC_CR |= RCC_CR_HSION;
break;
case RCC_LSE:
RCC_BDCR |= RCC_BDCR_LSEON;
break;
case RCC_LSI:
RCC_CSR |= RCC_CSR_LSION;
break;
case RCC_PLLSAI:
RCC_CR |= RCC_CR_PLLSAION;
break;
case RCC_PLLI2S:
RCC_CR |= RCC_CR_PLLI2SON;
break;
}
}
void rcc_osc_off(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CR &= ~RCC_CR_PLLON;
break;
case RCC_HSE:
RCC_CR &= ~RCC_CR_HSEON;
break;
case RCC_HSI:
RCC_CR &= ~RCC_CR_HSION;
break;
case RCC_LSE:
RCC_BDCR &= ~RCC_BDCR_LSEON;
break;
case RCC_LSI:
RCC_CSR &= ~RCC_CSR_LSION;
break;
case RCC_PLLSAI:
RCC_CR &= ~RCC_CR_PLLSAION;
break;
case RCC_PLLI2S:
RCC_CR &= ~RCC_CR_PLLI2SON;
break;
}
}
void rcc_css_enable(void)
{
RCC_CR |= RCC_CR_CSSON;
}
void rcc_css_disable(void)
{
RCC_CR &= ~RCC_CR_CSSON;
}
/**
* Set the dividers for the PLLI2S clock outputs
* @param n valid range depends on target device, check your RefManual.
* @param r valid range is 2..7
*/
void rcc_plli2s_config(uint16_t n, uint8_t r)
{
RCC_PLLI2SCFGR = (
((n & RCC_PLLI2SCFGR_PLLI2SN_MASK) << RCC_PLLI2SCFGR_PLLI2SN_SHIFT) |
((r & RCC_PLLI2SCFGR_PLLI2SR_MASK) << RCC_PLLI2SCFGR_PLLI2SR_SHIFT));
}
/**
* Set the dividers for the PLLSAI clock outputs
* divider p is only available on F4x9 parts, pass 0 for other parts.
* @param n valid range is 49..432
* @param p 0 if unused, @ref rcc_pllsaicfgr_pllsaip
* @param q valid range is 2..15
* @param r valid range is 2..7
* @sa rcc_pllsai_postscalers
*/
void rcc_pllsai_config(uint16_t n, uint16_t p, uint16_t q, uint16_t r)
{
RCC_PLLSAICFGR = (
((n & RCC_PLLSAICFGR_PLLSAIN_MASK) << RCC_PLLSAICFGR_PLLSAIN_SHIFT) |
((p & RCC_PLLSAICFGR_PLLSAIP_MASK) << RCC_PLLSAICFGR_PLLSAIP_SHIFT) |
((q & RCC_PLLSAICFGR_PLLSAIQ_MASK) << RCC_PLLSAICFGR_PLLSAIQ_SHIFT) |
((r & RCC_PLLSAICFGR_PLLSAIR_MASK) << RCC_PLLSAICFGR_PLLSAIR_SHIFT));
}
/**
* Set the dedicated dividers after the PLLSAI configuration.
*
* @param q dedicated PLLSAI divider, for either A or B
* @param r dedicated LCD-TFT divider, see LTDC
* @sa rcc_pllsai_config
*/
void rcc_pllsai_postscalers(uint8_t q, uint8_t r)
{
uint32_t reg32 = RCC_DCKCFGR;
reg32 &= ((RCC_DCKCFGR_PLLSAIDIVR_MASK << RCC_DCKCFGR_PLLSAIDIVR_SHIFT)
| (RCC_DCKCFGR_PLLSAIDIVQ_MASK << RCC_DCKCFGR_PLLSAIDIVQ_SHIFT));
RCC_DCKCFGR = reg32 | ((q << RCC_DCKCFGR_PLLSAIDIVQ_SHIFT) |
(r << RCC_DCKCFGR_PLLSAIDIVR_SHIFT));
}
void rcc_set_sysclk_source(uint32_t clk)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~((1 << 1) | (1 << 0));
RCC_CFGR = (reg32 | clk);
}
void rcc_set_pll_source(uint32_t pllsrc)
{
uint32_t reg32;
reg32 = RCC_PLLCFGR;
reg32 &= ~(1 << 22);
RCC_PLLCFGR = (reg32 | (pllsrc << 22));
}
void rcc_set_ppre2(uint32_t ppre2)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~((1 << 13) | (1 << 14) | (1 << 15));
RCC_CFGR = (reg32 | (ppre2 << 13));
}
void rcc_set_ppre1(uint32_t ppre1)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~((1 << 10) | (1 << 11) | (1 << 12));
RCC_CFGR = (reg32 | (ppre1 << 10));
}
void rcc_set_hpre(uint32_t hpre)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7));
RCC_CFGR = (reg32 | (hpre << 4));
}
void rcc_set_rtcpre(uint32_t rtcpre)
{
uint32_t reg32;
reg32 = RCC_CFGR;
reg32 &= ~((1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20));
RCC_CFGR = (reg32 | (rtcpre << 16));
}
/**
* Reconfigures the main PLL for a HSI source.
* Any reserved bits are kept at their reset values.
* @param pllm Divider for the main PLL input clock
* @param plln Main PLL multiplication factor for VCO
* @param pllp Main PLL divider for main system clock
* @param pllq Main PLL divider for USB OTG FS, SDMMC & RNG
* @param pllr Main PLL divider for DSI (for parts without DSI, provide 0 here)
*/
void rcc_set_main_pll_hsi(uint32_t pllm, uint32_t plln, uint32_t pllp,
uint32_t pllq, uint32_t pllr)
{
/* Use reset value if not legal, for parts without pllr */
if (pllr < 2) {
pllr = 2;
}
RCC_PLLCFGR = 0 | /* HSI */
((pllm & RCC_PLLCFGR_PLLM_MASK) << RCC_PLLCFGR_PLLM_SHIFT) |
((plln & RCC_PLLCFGR_PLLN_MASK) << RCC_PLLCFGR_PLLN_SHIFT) |
((((pllp >> 1) - 1) & RCC_PLLCFGR_PLLP_MASK) << RCC_PLLCFGR_PLLP_SHIFT) |
((pllq & RCC_PLLCFGR_PLLQ_MASK) << RCC_PLLCFGR_PLLQ_SHIFT) |
((pllr & RCC_PLLCFGR_PLLR_MASK) << RCC_PLLCFGR_PLLR_SHIFT);
}
/**
* Reconfigures the main PLL for a HSE source.
* Any reserved bits are kept at their reset values.
* @param pllm Divider for the main PLL input clock
* @param plln Main PLL multiplication factor for VCO
* @param pllp Main PLL divider for main system clock
* @param pllq Main PLL divider for USB OTG FS, SDMMC & RNG
* @param pllr Main PLL divider for DSI (for parts without DSI, provide 0 here)
*/
void rcc_set_main_pll_hse(uint32_t pllm, uint32_t plln, uint32_t pllp,
uint32_t pllq, uint32_t pllr)
{
/* Use reset value if not legal, for parts without pllr */
if (pllr < 2) {
pllr = 2;
}
RCC_PLLCFGR = RCC_PLLCFGR_PLLSRC | /* HSE */
((pllm & RCC_PLLCFGR_PLLM_MASK) << RCC_PLLCFGR_PLLM_SHIFT) |
((plln & RCC_PLLCFGR_PLLN_MASK) << RCC_PLLCFGR_PLLN_SHIFT) |
((((pllp >> 1) - 1) & RCC_PLLCFGR_PLLP_MASK) << RCC_PLLCFGR_PLLP_SHIFT) |
((pllq & RCC_PLLCFGR_PLLQ_MASK) << RCC_PLLCFGR_PLLQ_SHIFT) |
((pllr & RCC_PLLCFGR_PLLR_MASK) << RCC_PLLCFGR_PLLR_SHIFT);
}
uint32_t rcc_system_clock_source(void)
{
/* Return the clock source which is used as system clock. */
return (RCC_CFGR & 0x000c) >> 2;
}
/**
* Setup clocks to run from PLL.
*
* The arguments provide the pll source, multipliers, dividers, all that's
* needed to establish a system clock.
*
* @param clock clock information structure.
*/
void rcc_clock_setup_pll(const struct rcc_clock_scale *clock)
{
/* Enable internal high-speed oscillator (HSI). */
rcc_osc_on(RCC_HSI);
rcc_wait_for_osc_ready(RCC_HSI);
/* Select HSI as SYSCLK source. */
rcc_set_sysclk_source(RCC_CFGR_SW_HSI);
/* Enable external high-speed oscillator (HSE). */
if (clock->pll_source == RCC_CFGR_PLLSRC_HSE_CLK) {
rcc_osc_on(RCC_HSE);
rcc_wait_for_osc_ready(RCC_HSE);
}
/* Set the VOS scale mode */
rcc_periph_clock_enable(RCC_PWR);
pwr_set_vos_scale(clock->voltage_scale);
/*
* Set prescalers for AHB, ADC, APB1, APB2.
* Do this before touching the PLL (TODO: why?).
*/
rcc_set_hpre(clock->hpre);
rcc_set_ppre1(clock->ppre1);
rcc_set_ppre2(clock->ppre2);
/* Disable PLL oscillator before changing its configuration. */
rcc_osc_off(RCC_PLL);
/* Configure the PLL oscillator. */
if (clock->pll_source == RCC_CFGR_PLLSRC_HSE_CLK) {
rcc_set_main_pll_hse(clock->pllm, clock->plln,
clock->pllp, clock->pllq, clock->pllr);
} else {
rcc_set_main_pll_hsi(clock->pllm, clock->plln,
clock->pllp, clock->pllq, clock->pllr);
}
/* Enable PLL oscillator and wait for it to stabilize. */
rcc_osc_on(RCC_PLL);
rcc_wait_for_osc_ready(RCC_PLL);
/* Configure flash settings. */
if (clock->flash_config & FLASH_ACR_DCEN) {
flash_dcache_enable();
} else {
flash_dcache_disable();
}
if (clock->flash_config & FLASH_ACR_ICEN) {
flash_icache_enable();
} else {
flash_icache_disable();
}
flash_set_ws(clock->flash_config);
/* Select PLL as SYSCLK source. */
rcc_set_sysclk_source(RCC_CFGR_SW_PLL);
/* Wait for PLL clock to be selected. */
rcc_wait_for_sysclk_status(RCC_PLL);
/* Set the peripheral clock frequencies used. */
rcc_ahb_frequency = clock->ahb_frequency;
rcc_apb1_frequency = clock->apb1_frequency;
rcc_apb2_frequency = clock->apb2_frequency;
/* Disable internal high-speed oscillator. */
if (clock->pll_source == RCC_CFGR_PLLSRC_HSE_CLK) {
rcc_osc_off(RCC_HSI);
}
}
/**
* Setup clocks with the HSE.
*
* @deprecated replaced by rcc_clock_setup_pll as a drop in replacement.
* @see rcc_clock_setup_pll which supports HSI as well as HSE, using the same
* clock structures.
*/
void rcc_clock_setup_hse_3v3(const struct rcc_clock_scale *clock)
{
rcc_clock_setup_pll(clock);
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the USART at base specified.
* @param usart Base address of USART to get clock frequency for.
*/
uint32_t rcc_get_usart_clk_freq(uint32_t usart)
{
/* Handle values with selectable clocks. */
if (usart == USART1_BASE || usart == USART6_BASE) {
return rcc_apb2_frequency;
} else {
return rcc_apb1_frequency;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the Timer at base specified.
* @param timer Base address of TIM to get clock frequency for.
*/
uint32_t rcc_get_timer_clk_freq(uint32_t timer)
{
/* Handle APB1 timer clocks. */
if (timer >= TIM2_BASE && timer <= TIM14_BASE) {
uint8_t ppre1 = (RCC_CFGR >> RCC_CFGR_PPRE1_SHIFT) & RCC_CFGR_PPRE1_MASK;
return (ppre1 == RCC_CFGR_PPRE_DIV_NONE) ? rcc_apb1_frequency
: 2 * rcc_apb1_frequency;
} else {
uint8_t ppre2 = (RCC_CFGR >> RCC_CFGR_PPRE2_SHIFT) & RCC_CFGR_PPRE2_MASK;
return (ppre2 == RCC_CFGR_PPRE_DIV_NONE) ? rcc_apb2_frequency
: 2 * rcc_apb2_frequency;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the I2C device at base specified.
* @param i2c Base address of I2C to get clock frequency for.
*/
uint32_t rcc_get_i2c_clk_freq(uint32_t i2c __attribute__((unused)))
{
return rcc_apb1_frequency;
}
/*---------------------------------------------------------------------------*/
/** @brief Get the peripheral clock speed for the SPI device at base specified.
* @param spi Base address of SPI device to get clock frequency for (e.g. SPI1_BASE).
*/
uint32_t rcc_get_spi_clk_freq(uint32_t spi) {
if (spi == SPI2_BASE || spi == SPI3_BASE) {
return rcc_apb1_frequency;
} else {
return rcc_apb2_frequency;
}
}
/**@}*/

View File

@@ -0,0 +1,31 @@
/* This file is used for documentation purposes. It does not need
to be compiled. All source code is in the common area.
If there is any device specific code required it can be included here,
in which case this file must be added to the compile list. */
/** @defgroup rng_file RNG
@ingroup STM32F4xx
@brief <b>libopencm3 STM32F4xx RNG</b>
*/
/*
* 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/rng.h>

View File

@@ -0,0 +1,100 @@
/** @defgroup rtc_file RTC peripheral API
*
* @ingroup peripheral_apis
*
* @brief <b>libopencm3 STM32F4xx RTC</b>
*
* @version 1.0.0
*
* @date 4 March 2013
*
* 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/exti.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/rtc.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief Enable the wakeup timer
@warning You must unlock the registers before using this function
*/
void rtc_enable_wakeup_timer(void)
{
RTC_CR |= RTC_CR_WUTE | (RTC_CR_OSEL_WAKEUP << RTC_CR_OSEL_SHIFT);
rtc_enable_wakeup_timer_interrupt();
}
/*---------------------------------------------------------------------------*/
/** @brief Disable the wakeup timer
@warning You must unlock the registers before using this function
*/
void rtc_disable_wakeup_timer(void)
{
RTC_CR &= ~RTC_CR_WUTE;
rtc_disable_wakeup_timer_interrupt();
}
/*---------------------------------------------------------------------------*/
/** @brief Enable the wakeup timer interrupt
@warning You must unlock the registers before using this function
*/
void rtc_enable_wakeup_timer_interrupt(void)
{
/* FTFM:
* To enable the RTC Wakeup interrupt, the following sequence is
* required:
* 1. Configure and enable the EXTI Line 22 in interrupt mode and
* select the rising edge sensitivity.
*/
exti_enable_request(EXTI22);
exti_set_trigger(EXTI22, EXTI_TRIGGER_RISING);
/* 2. Configure and enable the RTC_WKUP IRQ channel in the NVIC. */
nvic_enable_irq(NVIC_RTC_WKUP_IRQ);
nvic_set_priority(NVIC_RTC_WKUP_IRQ, 1);
/* 3. Configure the RTC to generate the RTC wakeup timer event. */
RTC_CR |= RTC_CR_WUTIE; /* Enable the interrupt */
}
/*---------------------------------------------------------------------------*/
/** @brief Disable the wakeup timer interrupt
@warning You must unlock the registers before using this function
*/
void rtc_disable_wakeup_timer_interrupt(void)
{
/* 1. Disable EXTI Line 22 */
exti_disable_request(EXTI22);
/* 2. Disable RTC_WKUP IRQ channel in the NVIC. */
nvic_disable_irq(NVIC_RTC_WKUP_IRQ);
/* 3. Disable RTC wakeup timer event. */
RTC_CR &= ~RTC_CR_WUTIE;
}
/**@}*/

View File

@@ -0,0 +1,27 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
* Copyright (C) 2011 Fergus Noble <fergusnoble@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/scb.h>
static void pre_main(void)
{
/* Enable access to Floating-Point coprocessor. */
SCB_CPACR |= SCB_CPACR_FULL * (SCB_CPACR_CP10 | SCB_CPACR_CP11);
}

View File

@@ -0,0 +1,82 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
LIBNAME = libopencm3_stm32f7
SRCLIBDIR ?= ../..
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
# STM32F7 only supports single precision FPU
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv5-sp-d16
TGT_CFLAGS = -Os \
-Wall -Wextra -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../../include -fno-common \
-mcpu=cortex-m7 -mthumb $(FP_FLAGS) \
-Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DSTM32F7
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
ARFLAGS = rcs
OBJS += adc_common_v1.o adc_common_v1_multi.o adc_common_f47.o
OBJS += can.o
OBJS += crc_common_all.o crc_v2.o
OBJS += dac_common_all.o dac_common_v1.o
OBJS += dcmi_common_f47.o
OBJS += desig_common_all.o desig.o
OBJS += dma_common_f24.o
OBJS += dma2d_common_f47.o
OBJS += dsi_common_f47.o
OBJS += exti_common_all.o
OBJS += flash_common_all.o flash_common_f.o flash_common_f24.o flash.o
OBJS += fmc_common_f47.o
OBJS += gpio_common_all.o gpio_common_f0234.o
OBJS += i2c_common_v2.o
OBJS += iwdg_common_all.o
OBJS += lptimer_common_all.o
OBJS += ltdc_common_f47.o
OBJS += pwr.o rcc.o
OBJS += rcc_common_all.o
OBJS += rng_common_v1.o
OBJS += spi_common_all.o spi_common_v2.o
OBJS += timer_common_all.o
OBJS += usart_common_all.o usart_common_v2.o
OBJS += quadspi_common_v1.o
# Ethernet
OBJS += mac.o phy.o mac_stm32fxx7.o phy_ksz80x1.o
OBJS += usb.o usb_standard.o usb_control.o
OBJS += usb_audio.o
OBJS += usb_cdc.o
OBJS += usb_hid.o
OBJS += usb_midi.o
OBJS += usb_msc.o
OBJS += usb_dwc_common.o usb_f107.o usb_f207.o
VPATH += ../../usb:../:../../cm3:../common
VPATH += ../../ethernet
include ../../Makefile.include

Some files were not shown because too many files have changed in this diff Show More