git subrepo clone https://github.com/libopencm3/libopencm3.git
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:
550
libopencm3/lib/stm32/can.c
Normal file
550
libopencm3/lib/stm32/can.c
Normal file
@@ -0,0 +1,550 @@
|
||||
/** @defgroup can_file CAN
|
||||
|
||||
@ingroup STM32F_files
|
||||
|
||||
@brief <b>libopencm3 STM32Fxxx CAN</b>
|
||||
|
||||
@version 1.0.0
|
||||
|
||||
@author @htmlonly © @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);
|
||||
}
|
||||
124
libopencm3/lib/stm32/common/adc_common_f47.c
Normal file
124
libopencm3/lib/stm32/common/adc_common_f47.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/** @addtogroup adc_file ADC peripheral API
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
779
libopencm3/lib/stm32/common/adc_common_v1.c
Normal file
779
libopencm3/lib/stm32/common/adc_common_v1.c
Normal file
@@ -0,0 +1,779 @@
|
||||
/** @addtogroup adc_file ADC peripheral API
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @endhtmlonly
|
||||
2009 Edward Cheeseman <evbuilder@users.sourceforge.net>
|
||||
@author @htmlonly © @endhtmlonly
|
||||
2012 Ken Sarkies <ksarkies@internode.on.net>
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/**@}*/
|
||||
360
libopencm3/lib/stm32/common/adc_common_v1_multi.c
Normal file
360
libopencm3/lib/stm32/common/adc_common_v1_multi.c
Normal file
@@ -0,0 +1,360 @@
|
||||
/** @addtogroup adc_file ADC peripheral API
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
430
libopencm3/lib/stm32/common/adc_common_v2.c
Normal file
430
libopencm3/lib/stm32/common/adc_common_v2.c
Normal file
@@ -0,0 +1,430 @@
|
||||
/** @addtogroup adc_file ADC peripheral API
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
133
libopencm3/lib/stm32/common/adc_common_v2_multi.c
Normal file
133
libopencm3/lib/stm32/common/adc_common_v2_multi.c
Normal file
@@ -0,0 +1,133 @@
|
||||
/** @addtogroup adc_file ADC peripheral API
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
487
libopencm3/lib/stm32/common/cordic_common_v1.c
Normal file
487
libopencm3/lib/stm32/common/cordic_common_v1.c
Normal file
@@ -0,0 +1,487 @@
|
||||
/** @addtogroup cordic_file CORDIC peripheral API
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@brief HW accelerated maths trig/hyperbolic operations.
|
||||
@author @htmlonly © @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);
|
||||
}
|
||||
54
libopencm3/lib/stm32/common/crc_common_all.c
Normal file
54
libopencm3/lib/stm32/common/crc_common_all.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/** @addtogroup crc_file CRC peripheral API
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
116
libopencm3/lib/stm32/common/crc_v2.c
Normal file
116
libopencm3/lib/stm32/common/crc_v2.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/** @addtogroup crc_file CRC peripheral API
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
50
libopencm3/lib/stm32/common/crs_common_all.c
Normal file
50
libopencm3/lib/stm32/common/crs_common_all.c
Normal 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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
175
libopencm3/lib/stm32/common/crypto_common_f24.c
Normal file
175
libopencm3/lib/stm32/common/crypto_common_f24.c
Normal 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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
487
libopencm3/lib/stm32/common/dac_common_all.c
Normal file
487
libopencm3/lib/stm32/common/dac_common_all.c
Normal file
@@ -0,0 +1,487 @@
|
||||
/** @addtogroup dac_file DAC peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
* @brief Digital to Analog Converter
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2012 Ken Sarkies <ksarkies@internode.on.net>
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
81
libopencm3/lib/stm32/common/dac_common_v1.c
Normal file
81
libopencm3/lib/stm32/common/dac_common_v1.c
Normal file
@@ -0,0 +1,81 @@
|
||||
/** @addtogroup dac_file DAC peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
151
libopencm3/lib/stm32/common/dac_common_v2.c
Normal file
151
libopencm3/lib/stm32/common/dac_common_v2.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/** @addtogroup dac_file DAC peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
18
libopencm3/lib/stm32/common/dcmi_common_f47.c
Normal file
18
libopencm3/lib/stm32/common/dcmi_common_f47.c
Normal 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>
|
||||
|
||||
/**@}*/
|
||||
66
libopencm3/lib/stm32/common/desig_common_all.c
Normal file
66
libopencm3/lib/stm32/common/desig_common_all.c
Normal 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';
|
||||
}
|
||||
32
libopencm3/lib/stm32/common/desig_common_v1.c
Normal file
32
libopencm3/lib/stm32/common/desig_common_v1.c
Normal 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;
|
||||
}
|
||||
33
libopencm3/lib/stm32/common/dma2d_common_f47.c
Normal file
33
libopencm3/lib/stm32/common/dma2d_common_f47.c
Normal 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>
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**@}*/
|
||||
43
libopencm3/lib/stm32/common/dma_common_csel.c
Normal file
43
libopencm3/lib/stm32/common/dma_common_csel.c
Normal 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));
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
810
libopencm3/lib/stm32/common/dma_common_f24.c
Normal file
810
libopencm3/lib/stm32/common/dma_common_f24.c
Normal 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 © @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;
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
451
libopencm3/lib/stm32/common/dma_common_l1f013.c
Normal file
451
libopencm3/lib/stm32/common/dma_common_l1f013.c
Normal 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 © @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;
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
367
libopencm3/lib/stm32/common/dmamux.c
Normal file
367
libopencm3/lib/stm32/common/dmamux.c
Normal file
@@ -0,0 +1,367 @@
|
||||
/** @addtogroup dmamux_file DMAMUX peripheral API
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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);
|
||||
}
|
||||
|
||||
|
||||
/**@}*/
|
||||
34
libopencm3/lib/stm32/common/dsi_common_f47.c
Normal file
34
libopencm3/lib/stm32/common/dsi_common_f47.c
Normal 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>
|
||||
|
||||
/**@{*/
|
||||
|
||||
/**@}*/
|
||||
180
libopencm3/lib/stm32/common/exti_common_all.c
Normal file
180
libopencm3/lib/stm32/common/exti_common_all.c
Normal 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);
|
||||
};
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
71
libopencm3/lib/stm32/common/exti_common_v2.c
Normal file
71
libopencm3/lib/stm32/common/exti_common_v2.c
Normal file
@@ -0,0 +1,71 @@
|
||||
/** @addtogroup exti_file EXTI peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
*
|
||||
* @author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
699
libopencm3/lib/stm32/common/fdcan_common.c
Normal file
699
libopencm3/lib/stm32/common/fdcan_common.c
Normal 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);
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
|
||||
52
libopencm3/lib/stm32/common/flash_common_all.c
Normal file
52
libopencm3/lib/stm32/common/flash_common_all.c
Normal 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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
46
libopencm3/lib/stm32/common/flash_common_f.c
Normal file
46
libopencm3/lib/stm32/common/flash_common_f.c
Normal 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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
138
libopencm3/lib/stm32/common/flash_common_f01.c
Normal file
138
libopencm3/lib/stm32/common/flash_common_f01.c
Normal 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. */
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
291
libopencm3/lib/stm32/common/flash_common_f24.c
Normal file
291
libopencm3/lib/stm32/common/flash_common_f24.c
Normal 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();
|
||||
}
|
||||
/**@}*/
|
||||
59
libopencm3/lib/stm32/common/flash_common_idcache.c
Normal file
59
libopencm3/lib/stm32/common/flash_common_idcache.c
Normal 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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
164
libopencm3/lib/stm32/common/flash_common_l01.c
Normal file
164
libopencm3/lib/stm32/common/flash_common_l01.c
Normal 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();
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
111
libopencm3/lib/stm32/common/fmc_common_f47.c
Normal file
111
libopencm3/lib/stm32/common/fmc_common_f47.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/** @addtogroup fmc_file FMC peripheral API
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
152
libopencm3/lib/stm32/common/gpio_common_all.c
Normal file
152
libopencm3/lib/stm32/common/gpio_common_all.c
Normal file
@@ -0,0 +1,152 @@
|
||||
/** @addtogroup gpio_file GPIO peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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. */
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
206
libopencm3/lib/stm32/common/gpio_common_f0234.c
Normal file
206
libopencm3/lib/stm32/common/gpio_common_f0234.c
Normal file
@@ -0,0 +1,206 @@
|
||||
/** @addtogroup gpio_file
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2009
|
||||
Uwe Hermann <uwe@hermann-uwe.de>
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
164
libopencm3/lib/stm32/common/hash_common_f24.c
Normal file
164
libopencm3/lib/stm32/common/hash_common_f24.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/** @addtogroup hash_file HASH Peripheral API
|
||||
*
|
||||
* @ingroup peripheral_apis
|
||||
*
|
||||
* @author @htmlonly © @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];
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
540
libopencm3/lib/stm32/common/i2c_common_v1.c
Normal file
540
libopencm3/lib/stm32/common/i2c_common_v1.c
Normal file
@@ -0,0 +1,540 @@
|
||||
/** @addtogroup i2c_file I2C peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2010
|
||||
Thomas Otto <tommi@viadmin.org>
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**@}*/
|
||||
450
libopencm3/lib/stm32/common/i2c_common_v2.c
Normal file
450
libopencm3/lib/stm32/common/i2c_common_v2.c
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
152
libopencm3/lib/stm32/common/iwdg_common_all.c
Normal file
152
libopencm3/lib/stm32/common/iwdg_common_all.c
Normal file
@@ -0,0 +1,152 @@
|
||||
/** @addtogroup iwdg_file IWDG peripheral API
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
294
libopencm3/lib/stm32/common/lptimer_common_all.c
Normal file
294
libopencm3/lib/stm32/common/lptimer_common_all.c
Normal file
@@ -0,0 +1,294 @@
|
||||
/** @addtogroup lptimer_file LPTIM peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
*
|
||||
* @author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
92
libopencm3/lib/stm32/common/ltdc_common_f47.c
Normal file
92
libopencm3/lib/stm32/common/ltdc_common_f47.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/** @defgroup ltdc_file LTDC peripheral API
|
||||
*
|
||||
* @ingroup peripheral_apis
|
||||
*
|
||||
* @version 1.0.0
|
||||
*
|
||||
* @author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
112
libopencm3/lib/stm32/common/opamp_common_all.c
Normal file
112
libopencm3/lib/stm32/common/opamp_common_all.c
Normal 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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
56
libopencm3/lib/stm32/common/opamp_common_v1.c
Normal file
56
libopencm3/lib/stm32/common/opamp_common_v1.c
Normal 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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
52
libopencm3/lib/stm32/common/opamp_common_v2.c
Normal file
52
libopencm3/lib/stm32/common/opamp_common_v2.c
Normal 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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
206
libopencm3/lib/stm32/common/pwr_common_v1.c
Normal file
206
libopencm3/lib/stm32/common/pwr_common_v1.c
Normal file
@@ -0,0 +1,206 @@
|
||||
/** @addtogroup pwr_file PWR peripheral API
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
/**@}*/
|
||||
49
libopencm3/lib/stm32/common/pwr_common_v2.c
Normal file
49
libopencm3/lib/stm32/common/pwr_common_v2.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/** @addtogroup pwr_file PWR peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
*
|
||||
* @author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
12
libopencm3/lib/stm32/common/quadspi_common_v1.c
Normal file
12
libopencm3/lib/stm32/common/quadspi_common_v1.c
Normal 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;
|
||||
}
|
||||
288
libopencm3/lib/stm32/common/rcc_common_all.c
Normal file
288
libopencm3/lib/stm32/common/rcc_common_all.c
Normal 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
|
||||
121
libopencm3/lib/stm32/common/rng_common_v1.c
Normal file
121
libopencm3/lib/stm32/common/rng_common_v1.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
/**@}*/
|
||||
338
libopencm3/lib/stm32/common/rtc_common_l1f024.c
Normal file
338
libopencm3/lib/stm32/common/rtc_common_l1f024.c
Normal file
@@ -0,0 +1,338 @@
|
||||
/** @addtogroup rtc_file RTC peripheral API
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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);
|
||||
}
|
||||
/**@}*/
|
||||
681
libopencm3/lib/stm32/common/spi_common_all.c
Normal file
681
libopencm3/lib/stm32/common/spi_common_all.c
Normal file
@@ -0,0 +1,681 @@
|
||||
/** @addtogroup spi_file SPI peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2009
|
||||
Uwe Hermann <uwe@hermann-uwe.de>
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
127
libopencm3/lib/stm32/common/spi_common_v1.c
Normal file
127
libopencm3/lib/stm32/common/spi_common_v1.c
Normal file
@@ -0,0 +1,127 @@
|
||||
|
||||
/** @addtogroup spi_file SPI peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2009
|
||||
Uwe Hermann <uwe@hermann-uwe.de>
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
68
libopencm3/lib/stm32/common/spi_common_v1_frf.c
Normal file
68
libopencm3/lib/stm32/common/spi_common_v1_frf.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/** @addtogroup spi_file SPI peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2009
|
||||
Uwe Hermann <uwe@hermann-uwe.de>
|
||||
@author @htmlonly © @endhtmlonly 2012
|
||||
Ken Sarkies <ksarkies@internode.on.net>
|
||||
@author @htmlonly © @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
|
||||
|
||||
/**@}*/
|
||||
169
libopencm3/lib/stm32/common/spi_common_v2.c
Normal file
169
libopencm3/lib/stm32/common/spi_common_v2.c
Normal file
@@ -0,0 +1,169 @@
|
||||
/** @addtogroup spi_file SPI peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2009
|
||||
Uwe Hermann <uwe@hermann-uwe.de>
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
297
libopencm3/lib/stm32/common/st_usbfs_core.c
Normal file
297
libopencm3/lib/stm32/common/st_usbfs_core.c
Normal 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;
|
||||
}
|
||||
}
|
||||
76
libopencm3/lib/stm32/common/st_usbfs_core.h
Normal file
76
libopencm3/lib/stm32/common/st_usbfs_core.h
Normal 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
|
||||
1887
libopencm3/lib/stm32/common/timer_common_all.c
Normal file
1887
libopencm3/lib/stm32/common/timer_common_all.c
Normal file
File diff suppressed because it is too large
Load Diff
58
libopencm3/lib/stm32/common/timer_common_f0234.c
Normal file
58
libopencm3/lib/stm32/common/timer_common_f0234.c
Normal 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));
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
|
||||
52
libopencm3/lib/stm32/common/timer_common_f24.c
Normal file
52
libopencm3/lib/stm32/common/timer_common_f24.c
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
|
||||
427
libopencm3/lib/stm32/common/usart_common_all.c
Normal file
427
libopencm3/lib/stm32/common/usart_common_all.c
Normal file
@@ -0,0 +1,427 @@
|
||||
/** @addtogroup usart_file USART peripheral API
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
114
libopencm3/lib/stm32/common/usart_common_f124.c
Normal file
114
libopencm3/lib/stm32/common/usart_common_f124.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/** @addtogroup usart_file
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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);
|
||||
}
|
||||
|
||||
|
||||
/**@}*/
|
||||
72
libopencm3/lib/stm32/common/usart_common_fifos.c
Normal file
72
libopencm3/lib/stm32/common/usart_common_fifos.c
Normal 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);
|
||||
}
|
||||
306
libopencm3/lib/stm32/common/usart_common_v2.c
Normal file
306
libopencm3/lib/stm32/common/usart_common_v2.c
Normal file
@@ -0,0 +1,306 @@
|
||||
/** @addtogroup usart_file
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@author @htmlonly © @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);
|
||||
}
|
||||
|
||||
|
||||
/**@}*/
|
||||
65
libopencm3/lib/stm32/f0/Makefile
Normal file
65
libopencm3/lib/stm32/f0/Makefile
Normal 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
|
||||
|
||||
540
libopencm3/lib/stm32/f0/adc.c
Normal file
540
libopencm3/lib/stm32/f0/adc.c
Normal 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);
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/**@}*/
|
||||
64
libopencm3/lib/stm32/f0/comparator.c
Normal file
64
libopencm3/lib/stm32/f0/comparator.c
Normal 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;
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
156
libopencm3/lib/stm32/f0/flash.c
Normal file
156
libopencm3/lib/stm32/f0/flash.c
Normal 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 © @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. */
|
||||
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
32
libopencm3/lib/stm32/f0/i2c.c
Normal file
32
libopencm3/lib/stm32/f0/i2c.c
Normal 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>
|
||||
|
||||
699
libopencm3/lib/stm32/f0/rcc.c
Normal file
699
libopencm3/lib/stm32/f0/rcc.c
Normal 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;
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
31
libopencm3/lib/stm32/f0/syscfg.c
Normal file
31
libopencm3/lib/stm32/f0/syscfg.c
Normal 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>
|
||||
67
libopencm3/lib/stm32/f1/Makefile
Executable file
67
libopencm3/lib/stm32/f1/Makefile
Executable 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
|
||||
|
||||
443
libopencm3/lib/stm32/f1/adc.c
Normal file
443
libopencm3/lib/stm32/f1/adc.c
Normal file
@@ -0,0 +1,443 @@
|
||||
/** @addtogroup adc_file ADC peripheral API
|
||||
@ingroup peripheral_apis
|
||||
|
||||
@version 1.0.0
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2009
|
||||
Edward Cheeseman <evbuilder@users.sourceforge.net>
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/**@}*/
|
||||
|
||||
303
libopencm3/lib/stm32/f1/flash.c
Normal file
303
libopencm3/lib/stm32/f1/flash.c
Normal 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 © @endhtmlonly 2010
|
||||
* Thomas Otto <tommi@viadmin.org>
|
||||
* @author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
198
libopencm3/lib/stm32/f1/gpio.c
Normal file
198
libopencm3/lib/stm32/f1/gpio.c
Normal file
@@ -0,0 +1,198 @@
|
||||
/** @addtogroup gpio_file
|
||||
|
||||
@brief <b>libopencm3 STM32F1xx General Purpose I/O</b>
|
||||
|
||||
@version 1.0.0
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2009
|
||||
Uwe Hermann <uwe@hermann-uwe.de>
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
31
libopencm3/lib/stm32/f1/i2c.c
Normal file
31
libopencm3/lib/stm32/f1/i2c.c
Normal 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>
|
||||
1333
libopencm3/lib/stm32/f1/rcc.c
Normal file
1333
libopencm3/lib/stm32/f1/rcc.c
Normal file
File diff suppressed because it is too large
Load Diff
418
libopencm3/lib/stm32/f1/rtc.c
Normal file
418
libopencm3/lib/stm32/f1/rtc.c
Normal file
@@ -0,0 +1,418 @@
|
||||
/** @defgroup rtc_file RTC peripheral API
|
||||
*
|
||||
* @ingroup peripheral_apis
|
||||
*
|
||||
* @brief <b>libopencm3 STM32F1xx RTC</b>
|
||||
*
|
||||
* @author @htmlonly © @endhtmlonly 2010 Uwe Hermann <uwe@hermann-uwe.de>
|
||||
* @author @htmlonly © @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);
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
53
libopencm3/lib/stm32/f1/timer.c
Normal file
53
libopencm3/lib/stm32/f1/timer.c
Normal 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));
|
||||
}
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
62
libopencm3/lib/stm32/f2/Makefile
Normal file
62
libopencm3/lib/stm32/f2/Makefile
Normal 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
|
||||
31
libopencm3/lib/stm32/f2/crypto.c
Normal file
31
libopencm3/lib/stm32/f2/crypto.c
Normal 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>
|
||||
83
libopencm3/lib/stm32/f2/flash.c
Normal file
83
libopencm3/lib/stm32/f2/flash.c
Normal 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 © @endhtmlonly 2010
|
||||
* Thomas Otto <tommi@viadmin.org>
|
||||
* @author @htmlonly © @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();
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
32
libopencm3/lib/stm32/f2/i2c.c
Normal file
32
libopencm3/lib/stm32/f2/i2c.c
Normal 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>
|
||||
|
||||
444
libopencm3/lib/stm32/f2/rcc.c
Normal file
444
libopencm3/lib/stm32/f2/rcc.c
Normal 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 © @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;
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
31
libopencm3/lib/stm32/f2/rng.c
Normal file
31
libopencm3/lib/stm32/f2/rng.c
Normal 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>
|
||||
64
libopencm3/lib/stm32/f3/Makefile
Normal file
64
libopencm3/lib/stm32/f3/Makefile
Normal 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
|
||||
730
libopencm3/lib/stm32/f3/adc.c
Normal file
730
libopencm3/lib/stm32/f3/adc.c
Normal file
@@ -0,0 +1,730 @@
|
||||
/** @addtogroup adc_file ADC peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
*
|
||||
* @author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
117
libopencm3/lib/stm32/f3/flash.c
Normal file
117
libopencm3/lib/stm32/f3/flash.c
Normal 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 © @endhtmlonly 2010
|
||||
* Thomas Otto <tommi@viadmin.org>
|
||||
* @author @htmlonly © @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;
|
||||
}
|
||||
|
||||
|
||||
/**@}*/
|
||||
|
||||
32
libopencm3/lib/stm32/f3/i2c.c
Normal file
32
libopencm3/lib/stm32/f3/i2c.c
Normal 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>
|
||||
|
||||
581
libopencm3/lib/stm32/f3/rcc.c
Normal file
581
libopencm3/lib/stm32/f3/rcc.c
Normal 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;
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
27
libopencm3/lib/stm32/f3/vector_chipset.c
Normal file
27
libopencm3/lib/stm32/f3/vector_chipset.c
Normal 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);
|
||||
}
|
||||
79
libopencm3/lib/stm32/f4/Makefile
Normal file
79
libopencm3/lib/stm32/f4/Makefile
Normal 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
|
||||
66
libopencm3/lib/stm32/f4/crypto.c
Normal file
66
libopencm3/lib/stm32/f4/crypto.c
Normal 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;
|
||||
};
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
83
libopencm3/lib/stm32/f4/flash.c
Normal file
83
libopencm3/lib/stm32/f4/flash.c
Normal 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 © @endhtmlonly 2010
|
||||
* Thomas Otto <tommi@viadmin.org>
|
||||
* @author @htmlonly © @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();
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
31
libopencm3/lib/stm32/f4/i2c.c
Normal file
31
libopencm3/lib/stm32/f4/i2c.c
Normal 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>
|
||||
49
libopencm3/lib/stm32/f4/pwr.c
Normal file
49
libopencm3/lib/stm32/f4/pwr.c
Normal 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 © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
926
libopencm3/lib/stm32/f4/rcc.c
Normal file
926
libopencm3/lib/stm32/f4/rcc.c
Normal 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 © @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;
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
31
libopencm3/lib/stm32/f4/rng.c
Normal file
31
libopencm3/lib/stm32/f4/rng.c
Normal 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>
|
||||
100
libopencm3/lib/stm32/f4/rtc.c
Normal file
100
libopencm3/lib/stm32/f4/rtc.c
Normal 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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
27
libopencm3/lib/stm32/f4/vector_chipset.c
Normal file
27
libopencm3/lib/stm32/f4/vector_chipset.c
Normal 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);
|
||||
}
|
||||
82
libopencm3/lib/stm32/f7/Makefile
Normal file
82
libopencm3/lib/stm32/f7/Makefile
Normal 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
Reference in New Issue
Block a user