Add software
This commit is contained in:
@ -0,0 +1,81 @@
|
||||
/** @addtogroup crc_file
|
||||
|
||||
@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>
|
||||
|
||||
/**@{*/
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief CRC Reset.
|
||||
|
||||
Reset the CRC unit and forces the data register to all 1s.
|
||||
|
||||
*/
|
||||
|
||||
void crc_reset(void)
|
||||
{
|
||||
CRC_CR |= CRC_CR_RESET;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief CRC Calculate.
|
||||
|
||||
Writes a data word to the register, the write operation stalling until the
|
||||
computation is complete.
|
||||
|
||||
@param[in] data Unsigned int32.
|
||||
@returns int32 Computed CRC result
|
||||
*/
|
||||
|
||||
uint32_t crc_calculate(uint32_t data)
|
||||
{
|
||||
CRC_DR = data;
|
||||
/* Data sheet says this blocks until it's ready.... */
|
||||
return CRC_DR;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief CRC Calculate of a Block of Data.
|
||||
|
||||
Writes data words consecutively to the register, the write operation stalling
|
||||
until the computation of each word is complete.
|
||||
|
||||
@param[in] datap Unsigned int32. pointer to an array of 32 bit data words.
|
||||
@param[in] size int. Size of the array.
|
||||
@returns int32 Final computed CRC result
|
||||
*/
|
||||
|
||||
uint32_t crc_calculate_block(uint32_t *datap, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
CRC_DR = datap[i];
|
||||
}
|
||||
|
||||
return CRC_DR;
|
||||
}
|
||||
/**@}*/
|
||||
|
@ -0,0 +1,175 @@
|
||||
/** @addtogroup crypto_file
|
||||
*
|
||||
* @brief <b>libopencm3 STM32 Cryptographic controller</b>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*
|
||||
* @date 17 Jun 2013
|
||||
*
|
||||
* This library supports the cryptographic coprocessor system for the
|
||||
* STM32 series of ARM Cortex Microcontrollers
|
||||
*
|
||||
* LGPL License Terms @ref lgpl_license
|
||||
*/
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
#include <libopencm3/stm32/crypto.h>
|
||||
|
||||
#define CRYP_CR_ALGOMODE_MASK ((1 << 19) | CRYP_CR_ALGOMODE)
|
||||
|
||||
/**
|
||||
* @brief Wait, if the Controller is busy
|
||||
*/
|
||||
void crypto_wait_busy(void)
|
||||
{
|
||||
while (CRYP_SR & CRYP_SR_BUSY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set key value to the controller
|
||||
* @param[in] keysize enum crypto_keysize Specified size of the key.
|
||||
* @param[in] key uint64_t[] Key value (array of 4 items)
|
||||
*/
|
||||
void crypto_set_key(enum crypto_keysize keysize, uint64_t key[])
|
||||
{
|
||||
int i;
|
||||
|
||||
crypto_wait_busy();
|
||||
|
||||
CRYP_CR = (CRYP_CR & ~CRYP_CR_KEYSIZE) |
|
||||
(keysize << CRYP_CR_KEYSIZE_SHIFT);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
CRYP_KR(i) = key[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set Initialization Vector
|
||||
*
|
||||
* @param[in] iv uint64_t[] Initialization vector (array of 4 items)
|
||||
|
||||
* @note Cryptographic controller must be in disabled state
|
||||
*/
|
||||
void crypto_set_iv(uint64_t iv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
crypto_wait_busy();
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
CRYP_IVR(i) = iv[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the order of the data to be crypted
|
||||
*
|
||||
* @param[in] datatype enum crypto_datatype Specified datatype of the key.
|
||||
*/
|
||||
void crypto_set_datatype(enum crypto_datatype datatype)
|
||||
{
|
||||
CRYP_CR = (CRYP_CR & ~CRYP_CR_DATATYPE) |
|
||||
(datatype << CRYP_CR_DATATYPE_SHIFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the algoritm for Encryption/decryption
|
||||
*
|
||||
*@param[in] mode enum crypto_mode Mode of execution
|
||||
*/
|
||||
void crypto_set_algorithm(enum crypto_mode mode)
|
||||
{
|
||||
mode &= ~CRYP_CR_ALGOMODE_MASK;
|
||||
|
||||
if ((mode == DECRYPT_AES_ECB) || (mode == DECRYPT_AES_CBC)) {
|
||||
/* Unroll keys for the AES encoder for the user automatically */
|
||||
|
||||
CRYP_CR = (CRYP_CR & ~CRYP_CR_ALGOMODE_MASK) |
|
||||
CRYP_CR_ALGOMODE_AES_PREP;
|
||||
|
||||
crypto_start();
|
||||
crypto_wait_busy();
|
||||
/* module switches to DISABLE automatically */
|
||||
}
|
||||
/* set algo mode */
|
||||
CRYP_CR = (CRYP_CR & ~CRYP_CR_ALGOMODE_MASK) | mode;
|
||||
|
||||
/* flush buffers */
|
||||
CRYP_CR |= CRYP_CR_FFLUSH;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the cryptographic controller and start processing
|
||||
*/
|
||||
void crypto_start(void)
|
||||
{
|
||||
CRYP_CR |= CRYP_CR_CRYPEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the cryptographic controller and stop processing
|
||||
*/
|
||||
|
||||
void crypto_stop(void)
|
||||
{
|
||||
CRYP_CR &= ~CRYP_CR_CRYPEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start of encryption or decryption on data buffers
|
||||
*
|
||||
* This blocking method transfers input buffer of specified length to the
|
||||
* cryptographic coprocessor, and instructs him to begin of ciphering or
|
||||
* deciphering. It waits for data to be ready, and then fills the processed
|
||||
* data to output buffer.
|
||||
*
|
||||
* @param[in] inp uint32_t* Input array to crypt/decrypt.
|
||||
* @param[in] outp uint32_t* Output array with crypted/encrypted data.
|
||||
* @param[in] length uint32_t Length of the arrays
|
||||
*
|
||||
* @returns uint32_t Number of written words
|
||||
*/
|
||||
uint32_t crypto_process_block(uint32_t *inp, uint32_t *outp, uint32_t length)
|
||||
{
|
||||
uint32_t rd = 0, wr = 0;
|
||||
|
||||
/* Transfer the data */
|
||||
while (rd != length) {
|
||||
if ((wr < length) && (CRYP_SR & CRYP_SR_IFNF)) {
|
||||
CRYP_DIN = *inp++;
|
||||
wr++;
|
||||
}
|
||||
|
||||
if (CRYP_SR & CRYP_SR_OFNE) {
|
||||
*outp++ = CRYP_DOUT;
|
||||
rd++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait to finish - Not needed ? */
|
||||
crypto_wait_busy();
|
||||
|
||||
return wr;
|
||||
}
|
||||
|
||||
/**@}*/
|
@ -0,0 +1,500 @@
|
||||
/** @addtogroup dac_file
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2012 Ken Sarkies ksarkies@internode.on.net
|
||||
|
||||
This library supports the Digital to Analog Conversion System in the
|
||||
STM32F series of ARM Cortex Microcontrollers by ST Microelectronics.
|
||||
|
||||
The DAC is present only in a limited set of devices, notably some
|
||||
of the connection line, high density and XL devices.
|
||||
|
||||
Two DAC channels are available, however unlike the ADC channels these
|
||||
are separate DAC devices controlled by the same register block.
|
||||
|
||||
The DAC is on APB1. Its clock must be enabled in RCC and the GPIO
|
||||
ports set to alternate function output before it can be used.
|
||||
The digital output driver is disabled so the output driver mode
|
||||
(push-pull/open drain) is arbitrary.
|
||||
|
||||
The DAC has a holding (buffer) register and an output register from
|
||||
which the analog output is derived. The holding register must be
|
||||
loaded first. If triggering is enabled the output register is loaded
|
||||
from the holding register after a trigger occurs. If triggering is
|
||||
not enabled the holding register contents are transferred directly
|
||||
to the output register.
|
||||
|
||||
@note To avoid nonlinearities, do not allow outputs to range close
|
||||
to zero or V_analog.
|
||||
|
||||
@section dac_api_dual Dual Channel Conversion
|
||||
|
||||
There are dual modes in which both DACs are used to output data
|
||||
simultaneously or independently on both channels. The data must be
|
||||
presented according to the formats described in the datasheets. A
|
||||
convenience function @ref dac_load_data_buffer_dual is provided
|
||||
for software controlled use.
|
||||
|
||||
A variety of modes are available depending on whether independent
|
||||
or simultaneous output is desired, and whether waveforms are to be
|
||||
superimposed. Refer to the datasheets.
|
||||
|
||||
If DMA is used, only enable it for one of the channels. The DMA
|
||||
requests will then serve data in dual format to the data register
|
||||
dedicated to dual mode. The data will then be split and loaded to the
|
||||
appropriate DAC following the next trigger. There are three registers
|
||||
available, one for each of the formats: 12 bit right-aligned, 12 bit
|
||||
left-aligned and 8 bit right-aligned. The desired format is determined
|
||||
by specifying the appropriate register to the DMA controller.
|
||||
|
||||
@section dac_api_basic_ex Basic DAC handling API.
|
||||
|
||||
Set the DAC's GPIO port to any alternate function output mode. Enable the
|
||||
DAC clock. Enable the DAC, set a trigger source and load the buffer
|
||||
with the first value. After the DAC is triggered, load the buffer with
|
||||
the next value. This example uses software triggering and added noise.
|
||||
The trigger and further buffer load calls are made when data is to be
|
||||
sent out.
|
||||
|
||||
@code
|
||||
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
|
||||
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO4);
|
||||
rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_DACEN);
|
||||
dac_disable(CHANNEL_1);
|
||||
dac_set_waveform_characteristics(DAC_CR_MAMP1_8);
|
||||
dac_set_waveform_generation(DAC_CR_WAVE1_NOISE);
|
||||
dac_enable(CHANNEL_1);
|
||||
dac_set_trigger_source(DAC_CR_TSEL1_SW);
|
||||
dac_load_data_buffer_single(0, RIGHT12, CHANNEL_1);
|
||||
....
|
||||
dac_software_trigger(CHANNEL_1);
|
||||
dac_load_data_buffer_single(value, RIGHT12, CHANNEL_1);
|
||||
@endcode
|
||||
|
||||
@section dac_api_dma_ex Simultaneous Dual DAC with DMA.
|
||||
|
||||
This example in part sets up the DAC channel 1 DMA (DMA2 channel 3) to read
|
||||
16 bit data from memory into the right-aligned 8 bit dual register DAC_DHR8RD.
|
||||
Both DAC channels are enabled, and both triggers are set to the same timer
|
||||
2 input as required for simultaneous operation. DMA is enabled for DAC channel
|
||||
1 only to ensure that only one DMA request is generated.
|
||||
|
||||
@code
|
||||
dma_set_memory_size(DMA2,DMA_CHANNEL3,DMA_CCR_MSIZE_16BIT);
|
||||
dma_set_peripheral_size(DMA2,DMA_CHANNEL3,DMA_CCR_PSIZE_16BIT);
|
||||
dma_set_read_from_memory(DMA2,DMA_CHANNEL3);
|
||||
dma_set_peripheral_address(DMA2,DMA_CHANNEL3,(uint32_t) &DAC_DHR8RD);
|
||||
dma_enable_channel(DMA2,DMA_CHANNEL3);
|
||||
...
|
||||
dac_trigger_enable(CHANNEL_D);
|
||||
dac_set_trigger_source(DAC_CR_TSEL1_T2 | DAC_CR_TSEL2_T2);
|
||||
dac_dma_enable(CHANNEL_1);
|
||||
dac_enable(CHANNEL_D);
|
||||
@endcode
|
||||
|
||||
LGPL License Terms @ref lgpl_license
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2012 Ken Sarkies
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
#include <libopencm3/stm32/dac.h>
|
||||
|
||||
#define MASK8 0xFF
|
||||
#define MASK12 0xFFF
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DAC Channel Enable.
|
||||
|
||||
Enable a digital to analog converter channel. After setting this enable, the
|
||||
DAC requires a t<sub>wakeup</sub> time typically around 10 microseconds before
|
||||
it actually wakes up.
|
||||
|
||||
@param[in] dac_channel enum ::data_channel.
|
||||
*/
|
||||
|
||||
void dac_enable(data_channel dac_channel)
|
||||
{
|
||||
switch (dac_channel) {
|
||||
case CHANNEL_1:
|
||||
DAC_CR |= DAC_CR_EN1;
|
||||
break;
|
||||
case CHANNEL_2:
|
||||
DAC_CR |= DAC_CR_EN2;
|
||||
break;
|
||||
case CHANNEL_D:
|
||||
DAC_CR |= (DAC_CR_EN1 | DAC_CR_EN2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DAC Channel Disable.
|
||||
|
||||
Disable a digital to analog converter channel.
|
||||
|
||||
@param[in] dac_channel enum ::data_channel.
|
||||
*/
|
||||
|
||||
void dac_disable(data_channel dac_channel)
|
||||
{
|
||||
switch (dac_channel) {
|
||||
case CHANNEL_1:
|
||||
DAC_CR &= ~DAC_CR_EN1;
|
||||
break;
|
||||
case CHANNEL_2:
|
||||
DAC_CR &= ~DAC_CR_EN2;
|
||||
break;
|
||||
case CHANNEL_D:
|
||||
DAC_CR &= ~(DAC_CR_EN1 | DAC_CR_EN2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DAC Channel Output Buffer Enable.
|
||||
|
||||
Enable a digital to analog converter channel output drive buffer. This is an
|
||||
optional amplifying buffer that provides additional drive for the output
|
||||
signal. The buffer is enabled by default after a reset and needs to be
|
||||
explicitly disabled if required.
|
||||
|
||||
@param[in] dac_channel enum ::data_channel.
|
||||
*/
|
||||
|
||||
void dac_buffer_enable(data_channel dac_channel)
|
||||
{
|
||||
switch (dac_channel) {
|
||||
case CHANNEL_1:
|
||||
DAC_CR |= DAC_CR_BOFF1;
|
||||
break;
|
||||
case CHANNEL_2:
|
||||
DAC_CR |= DAC_CR_BOFF2;
|
||||
break;
|
||||
case CHANNEL_D:
|
||||
DAC_CR |= (DAC_CR_BOFF1 | DAC_CR_BOFF2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DAC Channel Output Buffer Disable.
|
||||
|
||||
Disable a digital to analog converter channel output drive buffer. Disabling
|
||||
this will reduce power consumption slightly and will increase the output
|
||||
impedance of the DAC. The buffers are enabled by default after a reset.
|
||||
|
||||
@param[in] dac_channel enum ::data_channel.
|
||||
*/
|
||||
|
||||
void dac_buffer_disable(data_channel dac_channel)
|
||||
{
|
||||
switch (dac_channel) {
|
||||
case CHANNEL_1:
|
||||
DAC_CR &= ~DAC_CR_BOFF1;
|
||||
break;
|
||||
case CHANNEL_2:
|
||||
DAC_CR &= ~DAC_CR_BOFF2;
|
||||
break;
|
||||
case CHANNEL_D:
|
||||
DAC_CR &= ~(DAC_CR_BOFF1 | DAC_CR_BOFF2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DAC Channel DMA Enable.
|
||||
|
||||
Enable a digital to analog converter channel DMA mode (connected to DMA2 channel
|
||||
3 for DAC channel 1 and DMA2 channel 4 for DAC channel 2). A DMA request is
|
||||
generated following an external trigger.
|
||||
|
||||
@param[in] dac_channel enum ::data_channel.
|
||||
*/
|
||||
|
||||
void dac_dma_enable(data_channel dac_channel)
|
||||
{
|
||||
switch (dac_channel) {
|
||||
case CHANNEL_1:
|
||||
DAC_CR |= DAC_CR_DMAEN1;
|
||||
break;
|
||||
case CHANNEL_2:
|
||||
DAC_CR |= DAC_CR_DMAEN2;
|
||||
break;
|
||||
case CHANNEL_D:
|
||||
DAC_CR |= (DAC_CR_DMAEN1 | DAC_CR_DMAEN2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DAC Channel DMA Disable.
|
||||
|
||||
Disable a digital to analog converter channel DMA mode.
|
||||
|
||||
@param[in] dac_channel enum ::data_channel.
|
||||
*/
|
||||
|
||||
void dac_dma_disable(data_channel dac_channel)
|
||||
{
|
||||
switch (dac_channel) {
|
||||
case CHANNEL_1:
|
||||
DAC_CR &= ~DAC_CR_DMAEN1;
|
||||
break;
|
||||
case CHANNEL_2:
|
||||
DAC_CR &= ~DAC_CR_DMAEN2;
|
||||
break;
|
||||
case CHANNEL_D:
|
||||
DAC_CR &= ~(DAC_CR_DMAEN1 | DAC_CR_DMAEN2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DAC Channel Trigger Enable.
|
||||
|
||||
Enable a digital to analog converter channel external trigger mode. This allows
|
||||
an external trigger to initiate register transfers from the buffer register to
|
||||
the DAC output register, followed by a DMA transfer to the buffer register if
|
||||
DMA is enabled. The trigger source must also be selected.
|
||||
|
||||
@param[in] dac_channel enum ::data_channel.
|
||||
*/
|
||||
|
||||
void dac_trigger_enable(data_channel dac_channel)
|
||||
{
|
||||
switch (dac_channel) {
|
||||
case CHANNEL_1:
|
||||
DAC_CR |= DAC_CR_TEN1;
|
||||
break;
|
||||
case CHANNEL_2:
|
||||
DAC_CR |= DAC_CR_TEN2;
|
||||
break;
|
||||
case CHANNEL_D:
|
||||
DAC_CR |= (DAC_CR_TEN1 | DAC_CR_TEN2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DAC Channel Trigger Disable.
|
||||
|
||||
Disable a digital to analog converter channel external trigger.
|
||||
|
||||
@param[in] dac_channel enum ::data_channel.
|
||||
*/
|
||||
|
||||
void dac_trigger_disable(data_channel dac_channel)
|
||||
{
|
||||
switch (dac_channel) {
|
||||
case CHANNEL_1:
|
||||
DAC_CR &= ~DAC_CR_TEN1;
|
||||
break;
|
||||
case CHANNEL_2:
|
||||
DAC_CR &= ~DAC_CR_TEN2;
|
||||
break;
|
||||
case CHANNEL_D:
|
||||
DAC_CR &= ~(DAC_CR_TEN1 | DAC_CR_TEN2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Set DAC Channel Trigger Source.
|
||||
|
||||
Sets the digital to analog converter trigger source, which can be taken from
|
||||
various timers, an external trigger or a software trigger.
|
||||
|
||||
@param[in] dac_trig_src uint32_t. Taken from @ref dac_trig2_sel or @ref
|
||||
dac_trig1_sel or a logical OR of one of each of these to set both channels
|
||||
simultaneously.
|
||||
*/
|
||||
|
||||
void dac_set_trigger_source(uint32_t dac_trig_src)
|
||||
{
|
||||
DAC_CR |= dac_trig_src;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Enable and Set DAC Channel Waveform Generation.
|
||||
|
||||
Enable the digital to analog converter waveform generation as either
|
||||
pseudo-random noise or triangular wave. These signals are superimposed on
|
||||
existing output values in the DAC output registers.
|
||||
|
||||
@note The DAC trigger must be enabled for this to work.
|
||||
|
||||
@param[in] dac_wave_ens uint32_t. Taken from @ref dac_wave1_en or @ref
|
||||
dac_wave2_en or a logical OR of one of each of these to set both channels
|
||||
simultaneously.
|
||||
*/
|
||||
|
||||
void dac_set_waveform_generation(uint32_t dac_wave_ens)
|
||||
{
|
||||
DAC_CR |= dac_wave_ens;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Disable DAC Channel Waveform Generation.
|
||||
|
||||
Disable a digital to analog converter channel superimposed waveform generation.
|
||||
|
||||
@param[in] dac_channel enum ::data_channel.
|
||||
*/
|
||||
|
||||
void dac_disable_waveform_generation(data_channel dac_channel)
|
||||
{
|
||||
switch (dac_channel) {
|
||||
case CHANNEL_1:
|
||||
DAC_CR &= ~DAC_CR_WAVE1_DIS;
|
||||
break;
|
||||
case CHANNEL_2:
|
||||
DAC_CR &= ~DAC_CR_WAVE2_DIS;
|
||||
break;
|
||||
case CHANNEL_D:
|
||||
DAC_CR &= ~(DAC_CR_WAVE1_DIS | DAC_CR_WAVE2_DIS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Set DAC Channel LFSR Mask or Triangle Wave Amplitude.
|
||||
|
||||
Sets the digital to analog converter superimposed waveform generation
|
||||
characteristics. @li If the noise generation mode is set, this sets the length
|
||||
of the PRBS sequence and hence the amplitude of the output noise signal.
|
||||
Default setting is length 1. @li If the triangle wave generation mode is set,
|
||||
this sets the amplitude of the output signal as 2^(n)-1 where n is the
|
||||
parameter value. Default setting is 1.
|
||||
|
||||
@note High amplitude levels of these waveforms can overload the DAC and distort
|
||||
the signal output.
|
||||
@note This must be called before enabling the DAC as the settings will then
|
||||
become read-only.
|
||||
@note The DAC trigger must be enabled for this to work.
|
||||
|
||||
@param[in] dac_mamp uint32_t. Taken from @ref dac_mamp2 or @ref dac_mamp1 or a
|
||||
logical OR of one of each of these to set both channels simultaneously.
|
||||
*/
|
||||
|
||||
void dac_set_waveform_characteristics(uint32_t dac_mamp)
|
||||
{
|
||||
DAC_CR |= dac_mamp;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Load DAC Data Register.
|
||||
|
||||
Loads the appropriate digital to analog converter data register with 12 or 8 bit
|
||||
data to be converted on a channel. The data can be aligned as follows:
|
||||
@li right-aligned 8 bit data in bits 0-7
|
||||
@li right-aligned 12 bit data in bits 0-11
|
||||
@li left aligned 12 bit data in bits 4-15
|
||||
|
||||
@param[in] dac_data uint16_t with appropriate alignment.
|
||||
@param[in] dac_data_format enum ::data_align. Alignment and size.
|
||||
@param[in] dac_channel enum ::data_channel.
|
||||
*/
|
||||
|
||||
void dac_load_data_buffer_single(uint16_t dac_data, data_align dac_data_format,
|
||||
data_channel dac_channel)
|
||||
{
|
||||
if (dac_channel == CHANNEL_1) {
|
||||
switch (dac_data_format) {
|
||||
case RIGHT8:
|
||||
DAC_DHR8R1 = dac_data;
|
||||
break;
|
||||
case RIGHT12:
|
||||
DAC_DHR12R1 = dac_data;
|
||||
break;
|
||||
case LEFT12:
|
||||
DAC_DHR12L1 = dac_data;
|
||||
break;
|
||||
}
|
||||
} else if (dac_channel == CHANNEL_2) {
|
||||
switch (dac_data_format) {
|
||||
case RIGHT8:
|
||||
DAC_DHR8R2 = dac_data;
|
||||
break;
|
||||
case RIGHT12:
|
||||
DAC_DHR12R2 = dac_data;
|
||||
break;
|
||||
case LEFT12:
|
||||
DAC_DHR12L2 = dac_data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Load DAC Dual Data Register.
|
||||
|
||||
Loads the appropriate digital to analog converter dual data register with 12 or
|
||||
8 bit data to be converted for both channels. This allows high bandwidth
|
||||
simultaneous or independent analog output. The data in both channels are aligned
|
||||
identically.
|
||||
|
||||
@param[in] dac_data1 uint16_t for channel 1 with appropriate alignment.
|
||||
@param[in] dac_data2 uint16_t for channel 2 with appropriate alignment.
|
||||
@param[in] dac_data_format enum ::data_align. Right or left aligned, and 8 or
|
||||
12 bit.
|
||||
*/
|
||||
|
||||
void dac_load_data_buffer_dual(uint16_t dac_data1, uint16_t dac_data2,
|
||||
data_align dac_data_format)
|
||||
{
|
||||
switch (dac_data_format) {
|
||||
case RIGHT8:
|
||||
DAC_DHR8RD = ((dac_data1 & MASK8) | ((dac_data2 & MASK8) << 8));
|
||||
break;
|
||||
case RIGHT12:
|
||||
DAC_DHR12RD = ((dac_data1 & MASK12) |
|
||||
((dac_data2 & MASK12) << 16));
|
||||
break;
|
||||
case LEFT12:
|
||||
DAC_DHR12LD = ((dac_data1 & MASK12) |
|
||||
((dac_data2 & MASK12) << 16));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Trigger the DAC by a Software Trigger.
|
||||
|
||||
If the trigger source is set to be a software trigger, cause a trigger to occur.
|
||||
The trigger is cleared by hardware after conversion.
|
||||
|
||||
@param[in] dac_channel enum ::data_channel.
|
||||
*/
|
||||
|
||||
void dac_software_trigger(data_channel dac_channel)
|
||||
{
|
||||
switch (dac_channel) {
|
||||
case CHANNEL_1:
|
||||
DAC_SWTRIGR |= DAC_SWTRIGR_SWTRIG1;
|
||||
break;
|
||||
case CHANNEL_2:
|
||||
DAC_SWTRIGR |= DAC_SWTRIGR_SWTRIG2;
|
||||
break;
|
||||
case CHANNEL_D:
|
||||
DAC_SWTRIGR |= (DAC_SWTRIGR_SWTRIG1 | DAC_SWTRIGR_SWTRIG2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
|
@ -0,0 +1,794 @@
|
||||
/** @addtogroup dma_file
|
||||
|
||||
@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 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;
|
||||
}
|
||||
/**@}*/
|
||||
|
@ -0,0 +1,435 @@
|
||||
/** @addtogroup dma_file
|
||||
|
||||
@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 explictly
|
||||
disabled here.
|
||||
|
||||
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
|
||||
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
|
||||
*/
|
||||
|
||||
void dma_enable_circular_mode(uint32_t dma, uint8_t channel)
|
||||
{
|
||||
DMA_CCR(dma, channel) |= DMA_CCR_CIRC;
|
||||
DMA_CCR(dma, channel) &= ~DMA_CCR_MEM2MEM;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DMA Channel Enable Transfers from a Peripheral
|
||||
|
||||
The data direction is set to read from a peripheral.
|
||||
|
||||
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
|
||||
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
|
||||
*/
|
||||
|
||||
void dma_set_read_from_peripheral(uint32_t dma, uint8_t channel)
|
||||
{
|
||||
DMA_CCR(dma, channel) &= ~DMA_CCR_DIR;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DMA Channel Enable Transfers from Memory
|
||||
|
||||
The data direction is set to read from memory.
|
||||
|
||||
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
|
||||
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
|
||||
*/
|
||||
|
||||
void dma_set_read_from_memory(uint32_t dma, uint8_t channel)
|
||||
{
|
||||
DMA_CCR(dma, channel) |= DMA_CCR_DIR;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DMA Channel Enable Interrupt on Transfer Error
|
||||
|
||||
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
|
||||
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
|
||||
*/
|
||||
|
||||
void dma_enable_transfer_error_interrupt(uint32_t dma, uint8_t channel)
|
||||
{
|
||||
DMA_CCR(dma, channel) |= DMA_CCR_TEIE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DMA Channel Disable Interrupt on Transfer Error
|
||||
|
||||
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
|
||||
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
|
||||
*/
|
||||
|
||||
void dma_disable_transfer_error_interrupt(uint32_t dma, uint8_t channel)
|
||||
{
|
||||
DMA_CCR(dma, channel) &= ~DMA_CCR_TEIE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DMA Channel Enable Interrupt on Transfer Half Complete
|
||||
|
||||
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
|
||||
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
|
||||
*/
|
||||
|
||||
void dma_enable_half_transfer_interrupt(uint32_t dma, uint8_t channel)
|
||||
{
|
||||
DMA_CCR(dma, channel) |= DMA_CCR_HTIE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DMA Channel Disable Interrupt on Transfer Half Complete
|
||||
|
||||
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
|
||||
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
|
||||
*/
|
||||
|
||||
void dma_disable_half_transfer_interrupt(uint32_t dma, uint8_t channel)
|
||||
{
|
||||
DMA_CCR(dma, channel) &= ~DMA_CCR_HTIE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DMA Channel Enable Interrupt on Transfer Complete
|
||||
|
||||
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
|
||||
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
|
||||
*/
|
||||
|
||||
void dma_enable_transfer_complete_interrupt(uint32_t dma, uint8_t channel)
|
||||
{
|
||||
DMA_CCR(dma, channel) |= DMA_CCR_TCIE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DMA Channel Disable Interrupt on Transfer Complete
|
||||
|
||||
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
|
||||
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
|
||||
*/
|
||||
|
||||
void dma_disable_transfer_complete_interrupt(uint32_t dma, uint8_t channel)
|
||||
{
|
||||
DMA_CCR(dma, channel) &= ~DMA_CCR_TCIE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DMA Channel Enable
|
||||
|
||||
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
|
||||
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
|
||||
*/
|
||||
|
||||
void dma_enable_channel(uint32_t dma, uint8_t channel)
|
||||
{
|
||||
DMA_CCR(dma, channel) |= DMA_CCR_EN;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DMA Channel Disable
|
||||
|
||||
@note The DMA channel registers retain their values when the channel is
|
||||
disabled.
|
||||
|
||||
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
|
||||
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
|
||||
*/
|
||||
|
||||
void dma_disable_channel(uint32_t dma, uint8_t channel)
|
||||
{
|
||||
DMA_CCR(dma, channel) &= ~DMA_CCR_EN;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DMA Channel Set the Peripheral Address
|
||||
|
||||
Set the address of the peripheral register to or from which data is to be
|
||||
transferred. Refer to the documentation for the specific peripheral.
|
||||
|
||||
@note The DMA channel must be disabled before setting this address. This
|
||||
function has no effect if the channel is enabled.
|
||||
|
||||
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
|
||||
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
|
||||
@param[in] address unsigned int32. Peripheral Address.
|
||||
*/
|
||||
|
||||
void dma_set_peripheral_address(uint32_t dma, uint8_t channel, uint32_t address)
|
||||
{
|
||||
if (!(DMA_CCR(dma, channel) & DMA_CCR_EN)) {
|
||||
DMA_CPAR(dma, channel) = (uint32_t) address;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DMA Channel Set the Base Memory Address
|
||||
|
||||
@note The DMA channel must be disabled before setting this address. This
|
||||
function has no effect if the channel is enabled.
|
||||
|
||||
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
|
||||
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
|
||||
@param[in] address unsigned int32. Memory Initial Address.
|
||||
*/
|
||||
|
||||
void dma_set_memory_address(uint32_t dma, uint8_t channel, uint32_t address)
|
||||
{
|
||||
if (!(DMA_CCR(dma, channel) & DMA_CCR_EN)) {
|
||||
DMA_CMAR(dma, channel) = (uint32_t) address;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief DMA Channel Set the Transfer Block Size
|
||||
|
||||
@note The DMA channel must be disabled before setting this count value. The
|
||||
count is not changed if the channel is enabled.
|
||||
|
||||
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
|
||||
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
|
||||
@param[in] number unsigned int16. Number of data words to transfer (65535
|
||||
maximum).
|
||||
*/
|
||||
|
||||
void dma_set_number_of_data(uint32_t dma, uint8_t channel, uint16_t number)
|
||||
{
|
||||
DMA_CNDTR(dma, channel) = number;
|
||||
}
|
||||
/**@}*/
|
||||
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
|
||||
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This provides the code for the "next gen" EXTI block provided in F2/F4/L1
|
||||
* devices. (differences only in the source selection)
|
||||
*/
|
||||
|
||||
#include <libopencm3/stm32/memorymap.h>
|
||||
#include <libopencm3/stm32/exti.h>
|
||||
#include <libopencm3/stm32/gpio.h>
|
||||
#if !defined(AFIO_BASE)
|
||||
# include <libopencm3/stm32/syscfg.h>
|
||||
#endif
|
||||
|
||||
void exti_set_trigger(uint32_t extis, enum exti_trigger_type trig)
|
||||
{
|
||||
switch (trig) {
|
||||
case EXTI_TRIGGER_RISING:
|
||||
EXTI_RTSR |= extis;
|
||||
EXTI_FTSR &= ~extis;
|
||||
break;
|
||||
case EXTI_TRIGGER_FALLING:
|
||||
EXTI_RTSR &= ~extis;
|
||||
EXTI_FTSR |= extis;
|
||||
break;
|
||||
case EXTI_TRIGGER_BOTH:
|
||||
EXTI_RTSR |= extis;
|
||||
EXTI_FTSR |= extis;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void exti_enable_request(uint32_t extis)
|
||||
{
|
||||
/* Enable interrupts. */
|
||||
EXTI_IMR |= extis;
|
||||
|
||||
/* Enable events. */
|
||||
EXTI_EMR |= extis;
|
||||
}
|
||||
|
||||
void exti_disable_request(uint32_t extis)
|
||||
{
|
||||
/* Disable interrupts. */
|
||||
EXTI_IMR &= ~extis;
|
||||
|
||||
/* Disable events. */
|
||||
EXTI_EMR &= ~extis;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the interrupt request by writing a 1 to the corresponding
|
||||
* pending bit register.
|
||||
*/
|
||||
void exti_reset_request(uint32_t extis)
|
||||
{
|
||||
EXTI_PR = extis;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the flag of a given EXTI interrupt.
|
||||
* */
|
||||
uint32_t exti_get_flag_status(uint32_t exti)
|
||||
{
|
||||
return EXTI_PR & exti;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remap an external interrupt line to the corresponding pin on the
|
||||
* specified GPIO port.
|
||||
*
|
||||
* TODO: This could be rewritten in fewer lines of code.
|
||||
*/
|
||||
void exti_select_source(uint32_t exti, uint32_t gpioport)
|
||||
{
|
||||
uint32_t line;
|
||||
for (line = 0; line < 16; line++) {
|
||||
if (!(exti & (1 << line))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t bits = 0, mask = 0x0F;
|
||||
|
||||
switch (gpioport) {
|
||||
case GPIOA:
|
||||
bits = 0;
|
||||
break;
|
||||
case GPIOB:
|
||||
bits = 1;
|
||||
break;
|
||||
case GPIOC:
|
||||
bits = 2;
|
||||
break;
|
||||
case GPIOD:
|
||||
bits = 3;
|
||||
break;
|
||||
#if defined(GPIOE) && defined(GPIO_PORT_E_BASE)
|
||||
case GPIOE:
|
||||
bits = 4;
|
||||
break;
|
||||
#endif
|
||||
#if defined(GPIOF) && defined(GPIO_PORT_F_BASE)
|
||||
case GPIOF:
|
||||
bits = 5;
|
||||
break;
|
||||
#endif
|
||||
#if defined(GPIOG) && defined(GPIO_PORT_G_BASE)
|
||||
case GPIOG:
|
||||
bits = 6;
|
||||
break;
|
||||
#endif
|
||||
#if defined(GPIOH) && defined(GPIO_PORT_H_BASE)
|
||||
case GPIOH:
|
||||
bits = 7;
|
||||
break;
|
||||
#endif
|
||||
#if defined(GPIOI) && defined(GPIO_PORT_I_BASE)
|
||||
case GPIOI:
|
||||
bits = 8;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t shift = (uint8_t)(4 * (line % 4));
|
||||
uint32_t reg = line / 4;
|
||||
bits <<= shift;
|
||||
mask <<= shift;
|
||||
|
||||
#if defined(AFIO_BASE)
|
||||
AFIO_EXTICR(reg) = (AFIO_EXTICR(reg) & ~mask) | bits;
|
||||
#else
|
||||
SYSCFG_EXTICR(reg) = (SYSCFG_EXTICR(reg) & ~mask) | bits;
|
||||
#endif
|
||||
};
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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_set_ws(uint32_t ws)
|
||||
{
|
||||
uint32_t reg32;
|
||||
|
||||
reg32 = FLASH_ACR;
|
||||
reg32 &= ~((1 << 0) | (1 << 1) | (1 << 2));
|
||||
reg32 |= ws;
|
||||
FLASH_ACR = reg32;
|
||||
}
|
||||
|
||||
void flash_unlock(void)
|
||||
{
|
||||
/* Clear the unlock sequence state. */
|
||||
FLASH_CR |= FLASH_CR_LOCK;
|
||||
|
||||
/* Authorize the FPEC access. */
|
||||
FLASH_KEYR = FLASH_KEYR_KEY1;
|
||||
FLASH_KEYR = FLASH_KEYR_KEY2;
|
||||
}
|
||||
|
||||
void flash_lock(void)
|
||||
{
|
||||
FLASH_CR |= FLASH_CR_LOCK;
|
||||
}
|
||||
|
||||
void flash_clear_pgperr_flag(void)
|
||||
{
|
||||
FLASH_SR |= FLASH_SR_PGPERR;
|
||||
}
|
||||
|
||||
void flash_clear_eop_flag(void)
|
||||
{
|
||||
FLASH_SR |= FLASH_SR_EOP;
|
||||
}
|
||||
|
||||
void flash_clear_bsy_flag(void)
|
||||
{
|
||||
FLASH_SR &= ~FLASH_SR_BSY;
|
||||
}
|
||||
|
||||
|
||||
void flash_wait_for_last_operation(void)
|
||||
{
|
||||
while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY);
|
||||
}
|
@ -0,0 +1,224 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
static inline void flash_set_program_size(uint32_t psize)
|
||||
{
|
||||
FLASH_CR &= ~(((1 << 0) | (1 << 1)) << 8);
|
||||
FLASH_CR |= psize;
|
||||
}
|
||||
|
||||
void flash_dcache_enable(void)
|
||||
{
|
||||
FLASH_ACR |= FLASH_ACR_DCE;
|
||||
}
|
||||
|
||||
void flash_dcache_disable(void)
|
||||
{
|
||||
FLASH_ACR &= ~FLASH_ACR_DCE;
|
||||
}
|
||||
|
||||
void flash_icache_enable(void)
|
||||
{
|
||||
FLASH_ACR |= FLASH_ACR_ICE;
|
||||
}
|
||||
|
||||
void flash_icache_disable(void)
|
||||
{
|
||||
FLASH_ACR &= ~FLASH_ACR_ICE;
|
||||
}
|
||||
|
||||
void flash_prefetch_enable(void)
|
||||
{
|
||||
FLASH_ACR |= FLASH_ACR_PRFTEN;
|
||||
}
|
||||
|
||||
void flash_prefetch_disable(void)
|
||||
{
|
||||
FLASH_ACR &= ~FLASH_ACR_PRFTEN;
|
||||
}
|
||||
|
||||
void flash_dcache_reset(void)
|
||||
{
|
||||
FLASH_ACR |= FLASH_ACR_DCRST;
|
||||
}
|
||||
|
||||
void flash_icache_reset(void)
|
||||
{
|
||||
FLASH_ACR |= FLASH_ACR_ICRST;
|
||||
}
|
||||
|
||||
void flash_clear_pgserr_flag(void)
|
||||
{
|
||||
FLASH_SR |= FLASH_SR_PGSERR;
|
||||
}
|
||||
|
||||
void flash_clear_pgaerr_flag(void)
|
||||
{
|
||||
FLASH_SR |= FLASH_SR_PGAERR;
|
||||
}
|
||||
|
||||
void flash_clear_wrperr_flag(void)
|
||||
{
|
||||
FLASH_SR |= FLASH_SR_WRPERR;
|
||||
}
|
||||
|
||||
void flash_clear_status_flags(void)
|
||||
{
|
||||
flash_clear_pgserr_flag();
|
||||
flash_clear_pgaerr_flag();
|
||||
flash_clear_wrperr_flag();
|
||||
flash_clear_pgperr_flag();
|
||||
flash_clear_eop_flag();
|
||||
flash_clear_bsy_flag();
|
||||
}
|
||||
|
||||
void flash_unlock_option_bytes(void)
|
||||
{
|
||||
/* Clear the unlock state. */
|
||||
FLASH_OPTCR |= FLASH_OPTCR_OPTLOCK;
|
||||
|
||||
/* Unlock option bytes. */
|
||||
FLASH_OPTKEYR = FLASH_OPTKEYR_KEY1;
|
||||
FLASH_OPTKEYR = FLASH_OPTKEYR_KEY2;
|
||||
}
|
||||
|
||||
void flash_lock_option_bytes(void)
|
||||
{
|
||||
FLASH_OPTCR |= FLASH_OPTCR_OPTLOCK;
|
||||
}
|
||||
|
||||
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 first half of the word. */
|
||||
MMIO64(address) = data;
|
||||
|
||||
/* Wait for the write to complete. */
|
||||
flash_wait_for_last_operation();
|
||||
|
||||
/* Disable writes to flash. */
|
||||
FLASH_CR &= ~FLASH_CR_PG;
|
||||
}
|
||||
|
||||
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 first half of 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;
|
||||
}
|
||||
|
||||
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. */
|
||||
}
|
||||
|
||||
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. */
|
||||
}
|
||||
|
||||
void flash_program(uint32_t address, uint8_t *data, uint32_t len)
|
||||
{
|
||||
/* TODO: Use dword and word size program operations where possible for
|
||||
* turbo speed.
|
||||
*/
|
||||
uint32_t i;
|
||||
for (i = 0; i < len; i++) {
|
||||
flash_program_byte(address+i, data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void flash_erase_sector(uint8_t sector, uint32_t program_size)
|
||||
{
|
||||
flash_wait_for_last_operation();
|
||||
flash_set_program_size(program_size);
|
||||
|
||||
FLASH_CR &= ~(0xF << 3);
|
||||
FLASH_CR |= (sector << 3) & 0x78;
|
||||
FLASH_CR |= FLASH_CR_SER;
|
||||
FLASH_CR |= FLASH_CR_STRT;
|
||||
|
||||
flash_wait_for_last_operation();
|
||||
FLASH_CR &= ~FLASH_CR_SER;
|
||||
FLASH_CR &= ~(0xF << 3);
|
||||
}
|
||||
|
||||
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. */
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
/** @addtogroup gpio_file
|
||||
|
||||
@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/>.
|
||||
*/
|
||||
|
||||
#define WEAK __attribute__((weak))
|
||||
|
||||
#include <libopencm3/stm32/gpio.h>
|
||||
|
||||
/**@{*/
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Set a Group of Pins Atomic
|
||||
|
||||
Set one or more pins of the given GPIO port to 1 in an atomic operation.
|
||||
|
||||
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
|
||||
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be changed, use logical OR '|' to separate
|
||||
them.
|
||||
*/
|
||||
void gpio_set(uint32_t gpioport, uint16_t gpios)
|
||||
{
|
||||
GPIO_BSRR(gpioport) = gpios;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Clear a Group of Pins Atomic
|
||||
|
||||
Clear one or more pins of the given GPIO port to 0 in an atomic operation.
|
||||
|
||||
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
|
||||
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be changed, use logical OR '|' to separate
|
||||
them.
|
||||
*/
|
||||
void gpio_clear(uint32_t gpioport, uint16_t gpios)
|
||||
{
|
||||
GPIO_BSRR(gpioport) = (gpios << 16);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Read a Group of Pins.
|
||||
|
||||
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
|
||||
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be read, use logical OR '|' to separate
|
||||
them.
|
||||
@return Unsigned int16 value of the pin values. The bit position of the pin
|
||||
value returned corresponds to the pin number.
|
||||
*/
|
||||
uint16_t gpio_get(uint32_t gpioport, uint16_t gpios)
|
||||
{
|
||||
return gpio_port_read(gpioport) & gpios;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Toggle a Group of Pins
|
||||
|
||||
Toggle one or more pins of the given GPIO port. This is not an atomic operation.
|
||||
|
||||
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
|
||||
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be changed, use logical OR '|' to separate
|
||||
them.
|
||||
*/
|
||||
void gpio_toggle(uint32_t gpioport, uint16_t gpios)
|
||||
{
|
||||
GPIO_ODR(gpioport) ^= gpios;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Read from a Port
|
||||
|
||||
Read the current value of the given GPIO port. Only the lower 16 bits contain
|
||||
valid pin data.
|
||||
|
||||
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
|
||||
@return Unsigned int16. The value held in the specified GPIO port.
|
||||
*/
|
||||
uint16_t gpio_port_read(uint32_t gpioport)
|
||||
{
|
||||
return (uint16_t)GPIO_IDR(gpioport);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Write to a Port
|
||||
|
||||
Write a value to the given GPIO port.
|
||||
|
||||
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
|
||||
@param[in] data Unsigned int16. The value to be written to the GPIO port.
|
||||
*/
|
||||
void gpio_port_write(uint32_t gpioport, uint16_t data)
|
||||
{
|
||||
GPIO_ODR(gpioport) = data;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Lock the Configuration of a Group of Pins
|
||||
|
||||
The configuration of one or more pins of the given GPIO port is locked. There
|
||||
is no mechanism to unlock these via software. Unlocking occurs at the next
|
||||
reset.
|
||||
|
||||
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
|
||||
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be locked, use logical OR '|' to separate
|
||||
them.
|
||||
*/
|
||||
void gpio_port_config_lock(uint32_t gpioport, uint16_t gpios)
|
||||
{
|
||||
uint32_t reg32;
|
||||
|
||||
/* Special "Lock Key Writing Sequence", see datasheet. */
|
||||
GPIO_LCKR(gpioport) = GPIO_LCKK | gpios; /* Set LCKK. */
|
||||
GPIO_LCKR(gpioport) = ~GPIO_LCKK & gpios; /* Clear LCKK. */
|
||||
GPIO_LCKR(gpioport) = GPIO_LCKK | gpios; /* Set LCKK. */
|
||||
reg32 = GPIO_LCKR(gpioport); /* Read LCKK. */
|
||||
reg32 = GPIO_LCKR(gpioport); /* Read LCKK again. */
|
||||
|
||||
/* Tell the compiler the variable is actually used. It will get
|
||||
* optimized out anyways.
|
||||
*/
|
||||
reg32 = reg32;
|
||||
|
||||
/* If (reg32 & GPIO_LCKK) is true, the lock is now active. */
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
@ -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_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;
|
||||
}
|
||||
/**@}*/
|
||||
|
@ -0,0 +1,161 @@
|
||||
/** @addtogroup hash_file
|
||||
|
||||
@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 |= 32 - validbits;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief HASH Init
|
||||
|
||||
Initializes the HASH processor.
|
||||
|
||||
*/
|
||||
|
||||
void hash_init()
|
||||
{
|
||||
HASH_CR |= HASH_CR_INIT;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief HASH Add data
|
||||
|
||||
Puts data into the HASH processor's queue.
|
||||
|
||||
@param[in] data unsigned int32. Hash input data.
|
||||
*/
|
||||
|
||||
void hash_add_data(uint32_t data)
|
||||
{
|
||||
HASH_DIN = data;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief HASH Digest
|
||||
|
||||
Starts the processing of the last data block.
|
||||
|
||||
*/
|
||||
|
||||
void hash_digest()
|
||||
{
|
||||
HASH_STR |= HASH_STR_DCAL;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief HASH Get Hash Result
|
||||
|
||||
Makes a copy of the resulting hash.
|
||||
|
||||
@param[out] data unsigned int32. Hash 4\5 words long depending on the algorithm.
|
||||
@param[in] algorithm unsigned int8. Hash algorithm: @ref hash_algorithm
|
||||
*/
|
||||
|
||||
void hash_get_result(uint32_t *data)
|
||||
{
|
||||
data[0] = HASH_HR[0];
|
||||
data[1] = HASH_HR[1];
|
||||
data[2] = HASH_HR[2];
|
||||
data[3] = HASH_HR[3];
|
||||
|
||||
if ((HASH_CR & HASH_CR_ALGO) == HASH_ALGO_SHA1) {
|
||||
data[4] = HASH_HR[4];
|
||||
}
|
||||
}
|
@ -0,0 +1,412 @@
|
||||
/** @addtogroup i2c_file
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2010
|
||||
Thomas Otto <tommi@viadmin.org>
|
||||
@author @htmlonly © @endhtmlonly 2012
|
||||
Ken Sarkies <ksarkies@internode.on.net>
|
||||
|
||||
Devices can have up to two I2C peripherals. The peripherals support SMBus and
|
||||
PMBus variants.
|
||||
|
||||
A peripheral begins after reset in Slave mode. To become a Master a start
|
||||
condition must be generated. The peripheral will remain in Master mode unless
|
||||
a multimaster contention is lost or a stop condition is generated.
|
||||
|
||||
@todo all sorts of lovely stuff like DMA, Interrupts, SMBus variant, Status
|
||||
register access, Error conditions
|
||||
|
||||
*/
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libopencm3/stm32/i2c.h>
|
||||
#include <libopencm3/stm32/rcc.h>
|
||||
|
||||
/**@{*/
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Reset.
|
||||
|
||||
The I2C peripheral and all its associated configuration registers are placed in
|
||||
the reset condition. The reset is effected via the RCC peripheral reset system.
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C peripheral identifier @ref i2c_reg_base.
|
||||
*/
|
||||
|
||||
void i2c_reset(uint32_t i2c)
|
||||
{
|
||||
switch (i2c) {
|
||||
case I2C1:
|
||||
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_I2C1RST);
|
||||
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_I2C1RST);
|
||||
break;
|
||||
case I2C2:
|
||||
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_I2C2RST);
|
||||
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_I2C2RST);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Peripheral Enable.
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
*/
|
||||
|
||||
void i2c_peripheral_enable(uint32_t i2c)
|
||||
{
|
||||
I2C_CR1(i2c) |= I2C_CR1_PE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Peripheral Disable.
|
||||
|
||||
This must not be reset while in Master mode until a communication has finished.
|
||||
In Slave mode, the peripheral is disabled only after communication has ended.
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
*/
|
||||
|
||||
void i2c_peripheral_disable(uint32_t i2c)
|
||||
{
|
||||
I2C_CR1(i2c) &= ~I2C_CR1_PE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Send Start Condition.
|
||||
|
||||
If in Master mode this will cause a restart condition to occur at the end of the
|
||||
current transmission. If in Slave mode, this will initiate a start condition
|
||||
when the current bus activity is completed.
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
*/
|
||||
|
||||
void i2c_send_start(uint32_t i2c)
|
||||
{
|
||||
I2C_CR1(i2c) |= I2C_CR1_START;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Send Stop Condition.
|
||||
|
||||
After the current byte transfer this will initiate a stop condition if in Master
|
||||
mode, or simply release the bus if in Slave mode.
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
*/
|
||||
|
||||
void i2c_send_stop(uint32_t i2c)
|
||||
{
|
||||
I2C_CR1(i2c) |= I2C_CR1_STOP;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Clear Stop Flag.
|
||||
|
||||
Clear the "Send Stop" flag in the I2C config register
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
*/
|
||||
void i2c_clear_stop(uint32_t i2c)
|
||||
{
|
||||
I2C_CR1(i2c) &= ~I2C_CR1_STOP;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Set the 7 bit Slave Address for the Peripheral.
|
||||
|
||||
This sets an address for Slave mode operation, in 7 bit form.
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
@param[in] slave Unsigned int8. Slave address 0...127.
|
||||
*/
|
||||
|
||||
void i2c_set_own_7bit_slave_address(uint32_t i2c, uint8_t slave)
|
||||
{
|
||||
I2C_OAR1(i2c) = (uint16_t)(slave << 1);
|
||||
I2C_OAR1(i2c) &= ~I2C_OAR1_ADDMODE;
|
||||
I2C_OAR1(i2c) |= (1 << 14); /* Datasheet: always keep 1 by software. */
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Set the 10 bit Slave Address for the Peripheral.
|
||||
|
||||
This sets an address for Slave mode operation, in 10 bit form.
|
||||
|
||||
@todo add "I2C_OAR1(i2c) |= (1 << 14);" as above
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
@param[in] slave Unsigned int16. Slave address 0...1023.
|
||||
*/
|
||||
|
||||
void i2c_set_own_10bit_slave_address(uint32_t i2c, uint16_t slave)
|
||||
{
|
||||
I2C_OAR1(i2c) = (uint16_t)(I2C_OAR1_ADDMODE | slave);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Set Peripheral Clock Frequency.
|
||||
|
||||
Set the peripheral clock frequency: 2MHz to 36MHz (the APB frequency). Note
|
||||
that this is <b> not </b> the I2C bus clock. This is set in conjunction with
|
||||
the Clock Control register to generate the Master bus clock, see @ref
|
||||
i2c_set_ccr
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
@param[in] freq Unsigned int8. Clock Frequency Setting @ref i2c_clock.
|
||||
*/
|
||||
|
||||
void i2c_set_clock_frequency(uint32_t i2c, uint8_t freq)
|
||||
{
|
||||
uint16_t reg16;
|
||||
reg16 = I2C_CR2(i2c) & 0xffc0; /* Clear bits [5:0]. */
|
||||
reg16 |= freq;
|
||||
I2C_CR2(i2c) = reg16;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Send Data.
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
@param[in] data Unsigned int8. Byte to send.
|
||||
*/
|
||||
|
||||
void i2c_send_data(uint32_t i2c, uint8_t data)
|
||||
{
|
||||
I2C_DR(i2c) = data;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Set Fast Mode.
|
||||
|
||||
Set the clock frequency to the high clock rate mode (up to 400kHz). The actual
|
||||
clock frequency must be set with @ref i2c_set_clock_frequency
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
*/
|
||||
|
||||
void i2c_set_fast_mode(uint32_t i2c)
|
||||
{
|
||||
I2C_CCR(i2c) |= I2C_CCR_FS;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Set Standard Mode.
|
||||
|
||||
Set the clock frequency to the standard clock rate mode (up to 100kHz). The
|
||||
actual clock frequency must be set with @ref i2c_set_clock_frequency
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
*/
|
||||
|
||||
void i2c_set_standard_mode(uint32_t i2c)
|
||||
{
|
||||
I2C_CCR(i2c) &= ~I2C_CCR_FS;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Set Bus Clock Frequency.
|
||||
|
||||
Set the bus clock frequency. This is a 12 bit number (0...4095) calculated
|
||||
from the formulae given in the STM32F1 reference manual in the description
|
||||
of the CCR field. It is a divisor of the peripheral clock frequency
|
||||
@ref i2c_set_clock_frequency modified by the fast mode setting
|
||||
@ref i2c_set_fast_mode
|
||||
|
||||
@todo provide additional API assitance to set the clock, eg macros
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
@param[in] freq Unsigned int16. Bus Clock Frequency Setting 0...4095.
|
||||
*/
|
||||
|
||||
void i2c_set_ccr(uint32_t i2c, uint16_t freq)
|
||||
{
|
||||
uint16_t reg16;
|
||||
reg16 = I2C_CCR(i2c) & 0xf000; /* Clear bits [11:0]. */
|
||||
reg16 |= freq;
|
||||
I2C_CCR(i2c) = reg16;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Set the Rise Time.
|
||||
|
||||
Set the maximum rise time on the bus according to the I2C specification, as 1
|
||||
more than the specified rise time in peripheral clock cycles. This is a 6 bit
|
||||
number.
|
||||
|
||||
@todo provide additional APIP assistance.
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
@param[in] trise Unsigned int16. Rise Time Setting 0...63.
|
||||
*/
|
||||
|
||||
void i2c_set_trise(uint32_t i2c, uint16_t trise)
|
||||
{
|
||||
I2C_TRISE(i2c) = trise;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Send the 7-bit Slave Address.
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
@param[in] slave Unsigned int16. Slave address 0...1023.
|
||||
@param[in] readwrite Unsigned int8. Single bit to instruct slave to receive or
|
||||
send @ref i2c_rw.
|
||||
*/
|
||||
|
||||
void i2c_send_7bit_address(uint32_t i2c, uint8_t slave, uint8_t readwrite)
|
||||
{
|
||||
I2C_DR(i2c) = (uint8_t)((slave << 1) | readwrite);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Get Data.
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
*/
|
||||
uint8_t i2c_get_data(uint32_t i2c)
|
||||
{
|
||||
return I2C_DR(i2c) & 0xff;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Enable Interrupt
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
@param[in] interrupt Unsigned int32. Interrupt to enable.
|
||||
*/
|
||||
void i2c_enable_interrupt(uint32_t i2c, uint32_t interrupt)
|
||||
{
|
||||
I2C_CR2(i2c) |= interrupt;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Disable Interrupt
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
@param[in] interrupt Unsigned int32. Interrupt to disable.
|
||||
*/
|
||||
void i2c_disable_interrupt(uint32_t i2c, uint32_t interrupt)
|
||||
{
|
||||
I2C_CR2(i2c) &= ~interrupt;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Enable ACK
|
||||
|
||||
Enables acking of own 7/10 bit address
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
*/
|
||||
void i2c_enable_ack(uint32_t i2c)
|
||||
{
|
||||
I2C_CR1(i2c) |= I2C_CR1_ACK;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Disable ACK
|
||||
|
||||
Disables acking of own 7/10 bit address
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
*/
|
||||
void i2c_disable_ack(uint32_t i2c)
|
||||
{
|
||||
I2C_CR1(i2c) &= ~I2C_CR1_ACK;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C NACK Next Byte
|
||||
|
||||
Causes the I2C controller to NACK the reception of the next byte
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
*/
|
||||
void i2c_nack_next(uint32_t i2c)
|
||||
{
|
||||
I2C_CR1(i2c) |= I2C_CR1_POS;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C NACK Next Byte
|
||||
|
||||
Causes the I2C controller to NACK the reception of the current byte
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
*/
|
||||
void i2c_nack_current(uint32_t i2c)
|
||||
{
|
||||
I2C_CR1(i2c) &= ~I2C_CR1_POS;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Set clock duty cycle
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
@param[in] dutycycle Unsigned int32. I2C duty cycle @ref i2c_duty_cycle.
|
||||
*/
|
||||
void i2c_set_dutycycle(uint32_t i2c, uint32_t dutycycle)
|
||||
{
|
||||
if (dutycycle == I2C_CCR_DUTY_DIV2) {
|
||||
I2C_CCR(i2c) &= ~I2C_CCR_DUTY;
|
||||
} else {
|
||||
I2C_CCR(i2c) |= I2C_CCR_DUTY;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Enable DMA
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
*/
|
||||
void i2c_enable_dma(uint32_t i2c)
|
||||
{
|
||||
I2C_CR2(i2c) |= I2C_CR2_DMAEN;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Disable DMA
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
*/
|
||||
void i2c_disable_dma(uint32_t i2c)
|
||||
{
|
||||
I2C_CR2(i2c) &= ~I2C_CR2_DMAEN;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Set DMA last transfer
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
*/
|
||||
void i2c_set_dma_last_transfer(uint32_t i2c)
|
||||
{
|
||||
I2C_CR2(i2c) |= I2C_CR2_LAST;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief I2C Clear DMA last transfer
|
||||
|
||||
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
|
||||
*/
|
||||
void i2c_clear_dma_last_transfer(uint32_t i2c)
|
||||
{
|
||||
I2C_CR2(i2c) &= ~I2C_CR2_LAST;
|
||||
}
|
||||
|
||||
/**@}*/
|
@ -0,0 +1,149 @@
|
||||
/** @addtogroup iwdg_file
|
||||
|
||||
@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)
|
||||
{
|
||||
uint32_t count, prescale, reload, exponent;
|
||||
|
||||
/* Set the count to represent ticks of the 32kHz LSI clock */
|
||||
count = (period << 5);
|
||||
|
||||
/* Strip off the first 12 bits to get the prescale value required */
|
||||
prescale = (count >> 12);
|
||||
if (prescale > 256) {
|
||||
exponent = IWDG_PR_DIV256; reload = COUNT_MASK;
|
||||
} else if (prescale > 128) {
|
||||
exponent = IWDG_PR_DIV256; reload = (count >> 8);
|
||||
} else if (prescale > 64) {
|
||||
exponent = IWDG_PR_DIV128; reload = (count >> 7);
|
||||
} else if (prescale > 32) {
|
||||
exponent = IWDG_PR_DIV64; reload = (count >> 6);
|
||||
} else if (prescale > 16) {
|
||||
exponent = IWDG_PR_DIV32; reload = (count >> 5);
|
||||
} else if (prescale > 8) {
|
||||
exponent = IWDG_PR_DIV16; reload = (count >> 4);
|
||||
} else if (prescale > 4) {
|
||||
exponent = IWDG_PR_DIV8; reload = (count >> 3);
|
||||
} else {
|
||||
exponent = IWDG_PR_DIV4; reload = (count >> 2);
|
||||
}
|
||||
|
||||
/* Avoid the undefined situation of a zero count */
|
||||
if (count == 0) {
|
||||
count = 1;
|
||||
}
|
||||
|
||||
while (iwdg_prescaler_busy());
|
||||
IWDG_KR = IWDG_KR_UNLOCK;
|
||||
IWDG_PR = exponent;
|
||||
while (iwdg_reload_busy());
|
||||
IWDG_KR = IWDG_KR_UNLOCK;
|
||||
IWDG_RLR = (reload & COUNT_MASK);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief IWDG Get Reload Register Status
|
||||
|
||||
@returns boolean: TRUE if the reload register is busy and unavailable for
|
||||
loading a new count value.
|
||||
*/
|
||||
|
||||
bool iwdg_reload_busy(void)
|
||||
{
|
||||
return IWDG_SR & IWDG_SR_RVU;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief IWDG Get Prescaler Register Status
|
||||
|
||||
@returns boolean: TRUE if the prescaler register is busy and unavailable for
|
||||
loading a new period value.
|
||||
*/
|
||||
|
||||
bool iwdg_prescaler_busy(void)
|
||||
{
|
||||
return IWDG_SR & IWDG_SR_PVU;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief IWDG reset Watchdog Timer
|
||||
|
||||
The watchdog timer is reset. The counter restarts from the value in the reload
|
||||
register.
|
||||
*/
|
||||
|
||||
void iwdg_reset(void)
|
||||
{
|
||||
IWDG_KR = IWDG_KR_RESET;
|
||||
}
|
||||
/**@}*/
|
||||
|
@ -0,0 +1,205 @@
|
||||
/** @addtogroup pwr_file PWR
|
||||
|
||||
@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;
|
||||
}
|
||||
/**@}*/
|
@ -0,0 +1,123 @@
|
||||
/** @addtogroup rtc_file
|
||||
|
||||
@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>
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Set RTC prescalars.
|
||||
|
||||
This sets the RTC synchronous and asynchronous prescalars.
|
||||
*/
|
||||
|
||||
void rtc_set_prescaler(uint32_t sync, uint32_t async)
|
||||
{
|
||||
/*
|
||||
* Even if only one of the two fields needs to be changed,
|
||||
* 2 separate write accesses must be performed to the RTC_PRER register.
|
||||
*/
|
||||
RTC_PRER = (sync & RTC_PRER_PREDIV_S_MASK);
|
||||
RTC_PRER |= (async << RTC_PRER_PREDIV_A_SHIFT);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Wait for RTC registers to be synchronised with the APB1 bus
|
||||
|
||||
Time and Date are accessed through shadow registers which must be synchronized
|
||||
*/
|
||||
|
||||
void rtc_wait_for_synchro(void)
|
||||
{
|
||||
/* Unlock RTC registers */
|
||||
RTC_WPR = 0xca;
|
||||
RTC_WPR = 0x53;
|
||||
|
||||
RTC_ISR &= ~(RTC_ISR_RSF);
|
||||
|
||||
while (!(RTC_ISR & RTC_ISR_RSF));
|
||||
|
||||
/* disable write protection again */
|
||||
RTC_WPR = 0xff;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Unlock write access to the RTC registers
|
||||
|
||||
*/
|
||||
void rtc_unlock(void)
|
||||
{
|
||||
RTC_WPR = 0xca;
|
||||
RTC_WPR = 0x53;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Lock write access to the RTC registers
|
||||
|
||||
*/
|
||||
void rtc_lock(void)
|
||||
{
|
||||
RTC_WPR = 0xff;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Sets the wakeup time auto-reload value
|
||||
|
||||
*/
|
||||
void rtc_set_wakeup_time(uint16_t wkup_time, uint8_t rtc_cr_wucksel)
|
||||
{
|
||||
/* FTFM:
|
||||
* The following sequence is required to configure or change the wakeup
|
||||
* timer auto-reload value (WUT[15:0] in RTC_WUTR):
|
||||
* 1. Clear WUTE in RTC_CR to disable the wakeup timer.
|
||||
*/
|
||||
RTC_CR &= ~RTC_CR_WUTE;
|
||||
/* 2. Poll WUTWF until it is set in RTC_ISR to make sure the access to
|
||||
* wakeup auto-reload counter and to WUCKSEL[2:0] bits is allowed.
|
||||
* It takes around 2 RTCCLK clock cycles (due to clock
|
||||
* synchronization).
|
||||
*/
|
||||
while (!((RTC_ISR) & (RTC_ISR_WUTWF)));
|
||||
/* 3. Program the wakeup auto-reload value WUT[15:0], and the wakeup
|
||||
* clock selection (WUCKSEL[2:0] bits in RTC_CR).Set WUTE in RTC_CR
|
||||
* to enable the timer again. The wakeup timer restarts
|
||||
* down-counting.
|
||||
*/
|
||||
RTC_WUTR = wkup_time;
|
||||
RTC_CR |= (rtc_cr_wucksel << RTC_CR_WUCLKSEL_SHIFT);
|
||||
RTC_CR |= RTC_CR_WUTE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Clears the wakeup flag
|
||||
|
||||
@details This function should be called first in the rtc_wkup_isr()
|
||||
*/
|
||||
void rtc_clear_wakeup_flag(void)
|
||||
{
|
||||
RTC_ISR &= ~RTC_ISR_WUTF;
|
||||
}
|
||||
|
||||
/**@}*/
|
@ -0,0 +1,698 @@
|
||||
/** @addtogroup spi_file
|
||||
|
||||
@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: 1Mbps, positive clock polarity, leading edge trigger, 8-bit words,
|
||||
LSB first.
|
||||
@code
|
||||
spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
|
||||
SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT,
|
||||
SPI_CR1_LSBFIRST);
|
||||
spi_write(SPI1, 0x55); // 8-bit write
|
||||
spi_write(SPI1, 0xaa88); // 16-bit write
|
||||
reg8 = spi_read(SPI1); // 8-bit read
|
||||
reg16 = spi_read(SPI1); // 16-bit read
|
||||
@endcode
|
||||
|
||||
@todo need additional functions to aid ISRs in retrieving status
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libopencm3/stm32/spi.h>
|
||||
#include <libopencm3/stm32/rcc.h>
|
||||
|
||||
/*
|
||||
* SPI and I2S code.
|
||||
*
|
||||
* Examples:
|
||||
* spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
|
||||
* SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT,
|
||||
* SPI_CR1_LSBFIRST);
|
||||
* spi_write(SPI1, 0x55); // 8-bit write
|
||||
* spi_write(SPI1, 0xaa88); // 16-bit write
|
||||
* reg8 = spi_read(SPI1); // 8-bit read
|
||||
* reg16 = spi_read(SPI1); // 16-bit read
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Reset.
|
||||
|
||||
The SPI peripheral and all its associated configuration registers are placed in
|
||||
the reset condition. The reset is effected via the RCC peripheral reset system.
|
||||
|
||||
@param[in] spi_peripheral Unsigned int32. SPI peripheral identifier @ref
|
||||
spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_reset(uint32_t spi_peripheral)
|
||||
{
|
||||
/* there is another way of resetting mechanism on F0. It will be extended to all
|
||||
families of stm32 and this function will be deprecated and deleted in the
|
||||
future.*/
|
||||
#if !defined(STM32F0)
|
||||
switch (spi_peripheral) {
|
||||
case SPI1:
|
||||
rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_SPI1RST);
|
||||
rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_SPI1RST);
|
||||
break;
|
||||
case SPI2:
|
||||
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_SPI2RST);
|
||||
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_SPI2RST);
|
||||
break;
|
||||
#if defined(STM32F1) || defined(STM32F2) || defined(STM32F3) || defined(STM32F4)
|
||||
case SPI3:
|
||||
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_SPI3RST);
|
||||
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_SPI3RST);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* TODO: Error handling? */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Enable.
|
||||
|
||||
The SPI peripheral is enabled.
|
||||
|
||||
@todo Error handling?
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_enable(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) |= SPI_CR1_SPE; /* Enable SPI. */
|
||||
}
|
||||
|
||||
/* TODO: Error handling? */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Disable.
|
||||
|
||||
The SPI peripheral is disabled.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_disable(uint32_t spi)
|
||||
{
|
||||
uint32_t reg32;
|
||||
|
||||
reg32 = SPI_CR1(spi);
|
||||
reg32 &= ~(SPI_CR1_SPE); /* Disable SPI. */
|
||||
SPI_CR1(spi) = reg32;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Clean Disable.
|
||||
|
||||
Disable the SPI peripheral according to the procedure in section 23.3.8 of the
|
||||
reference manual. This prevents corruption of any ongoing transfers and
|
||||
prevents the BSY flag from becoming unreliable.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
@returns data Unsigned int16. 8 or 16 bit data from final read.
|
||||
*/
|
||||
|
||||
uint16_t spi_clean_disable(uint32_t spi)
|
||||
{
|
||||
/* Wait to receive last data */
|
||||
while (!(SPI_SR(spi) & SPI_SR_RXNE));
|
||||
|
||||
uint16_t data = SPI_DR(spi);
|
||||
|
||||
/* Wait to transmit last data */
|
||||
while (!(SPI_SR(spi) & SPI_SR_TXE));
|
||||
|
||||
/* Wait until not busy */
|
||||
while (SPI_SR(spi) & SPI_SR_BSY);
|
||||
|
||||
SPI_CR1(spi) &= ~SPI_CR1_SPE;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Data Write.
|
||||
|
||||
Data is written to the SPI interface.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
@param[in] data Unsigned int16. 8 or 16 bit data to be written.
|
||||
*/
|
||||
|
||||
void spi_write(uint32_t spi, uint16_t data)
|
||||
{
|
||||
/* Write data (8 or 16 bits, depending on DFF) into DR. */
|
||||
SPI_DR(spi) = data;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Data Write with Blocking.
|
||||
|
||||
Data is written to the SPI interface after the previous write transfer has
|
||||
finished.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
@param[in] data Unsigned int16. 8 or 16 bit data to be written.
|
||||
*/
|
||||
|
||||
void spi_send(uint32_t spi, uint16_t data)
|
||||
{
|
||||
/* Wait for transfer finished. */
|
||||
while (!(SPI_SR(spi) & SPI_SR_TXE));
|
||||
|
||||
/* Write data (8 or 16 bits, depending on DFF) into DR. */
|
||||
SPI_DR(spi) = data;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Data Read.
|
||||
|
||||
Data is read from the SPI interface after the incoming transfer has finished.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
@returns data Unsigned int16. 8 or 16 bit data.
|
||||
*/
|
||||
|
||||
uint16_t spi_read(uint32_t spi)
|
||||
{
|
||||
/* Wait for transfer finished. */
|
||||
while (!(SPI_SR(spi) & SPI_SR_RXNE));
|
||||
|
||||
/* Read the data (8 or 16 bits, depending on DFF bit) from DR. */
|
||||
return SPI_DR(spi);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Data Write and Read Exchange.
|
||||
|
||||
Data is written to the SPI interface, then a read is done after the incoming
|
||||
transfer has finished.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
@param[in] data Unsigned int16. 8 or 16 bit data to be written.
|
||||
@returns data Unsigned int16. 8 or 16 bit data.
|
||||
*/
|
||||
|
||||
uint16_t spi_xfer(uint32_t spi, uint16_t data)
|
||||
{
|
||||
spi_write(spi, data);
|
||||
|
||||
/* Wait for transfer finished. */
|
||||
while (!(SPI_SR(spi) & SPI_SR_RXNE));
|
||||
|
||||
/* Read the data (8 or 16 bits, depending on DFF bit) from DR. */
|
||||
return SPI_DR(spi);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set Bidirectional Simplex Mode.
|
||||
|
||||
The SPI peripheral is set for bidirectional transfers in two-wire simplex mode
|
||||
(using a clock wire and a bidirectional data wire).
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_bidirectional_mode(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) |= SPI_CR1_BIDIMODE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set Unidirectional Mode.
|
||||
|
||||
The SPI peripheral is set for unidirectional transfers. This is used in full
|
||||
duplex mode or when the SPI is placed in two-wire simplex mode that uses a
|
||||
clock wire and a unidirectional data wire.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_unidirectional_mode(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) &= ~SPI_CR1_BIDIMODE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set Bidirectional Simplex Receive Only Mode.
|
||||
|
||||
The SPI peripheral is set for bidirectional transfers in two-wire simplex mode
|
||||
(using a clock wire and a bidirectional data wire), and is placed in a receive
|
||||
state.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_bidirectional_receive_only_mode(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) |= SPI_CR1_BIDIMODE;
|
||||
SPI_CR1(spi) &= ~SPI_CR1_BIDIOE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set Bidirectional Simplex Receive Only Mode.
|
||||
|
||||
The SPI peripheral is set for bidirectional transfers in two-wire simplex mode
|
||||
(using a clock wire and a bidirectional data wire), and is placed in a transmit
|
||||
state.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_bidirectional_transmit_only_mode(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) |= SPI_CR1_BIDIMODE;
|
||||
SPI_CR1(spi) |= SPI_CR1_BIDIOE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Enable the CRC.
|
||||
|
||||
The SPI peripheral is set to use a CRC field for transmit and receive.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_enable_crc(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) |= SPI_CR1_CRCEN;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Disable the CRC.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_disable_crc(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) &= ~SPI_CR1_CRCEN;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Next Transmit is a Data Word
|
||||
|
||||
The next transmission to take place is a data word from the transmit buffer.
|
||||
This must be called before transmission to distinguish between sending
|
||||
of a data or CRC word.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_next_tx_from_buffer(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) &= ~SPI_CR1_CRCNEXT;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Next Transmit is a CRC Word
|
||||
|
||||
The next transmission to take place is a crc word from the hardware crc unit.
|
||||
This must be called before transmission to distinguish between sending
|
||||
of a data or CRC word.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_next_tx_from_crc(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) |= SPI_CR1_CRCNEXT;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set Full Duplex (3-wire) Mode
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_full_duplex_mode(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) &= ~SPI_CR1_RXONLY;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set Receive Only Mode for Simplex (2-wire) Unidirectional
|
||||
Transfers
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_receive_only_mode(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) |= SPI_CR1_RXONLY;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Enable Slave Management by Hardware
|
||||
|
||||
In slave mode the NSS hardware input is used as a select enable for the slave.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_disable_software_slave_management(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) &= ~SPI_CR1_SSM;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Enable Slave Management by Software
|
||||
|
||||
In slave mode the NSS hardware input is replaced by an internal software
|
||||
enable/disable of the slave (@ref spi_set_nss_high).
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_enable_software_slave_management(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) |= SPI_CR1_SSM;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set the Software NSS Signal High
|
||||
|
||||
In slave mode, and only when software slave management is used, this replaces
|
||||
the NSS signal with a slave select enable signal.
|
||||
|
||||
@todo these should perhaps be combined with an SSM enable as it is meaningless
|
||||
otherwise
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_nss_high(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) |= SPI_CR1_SSI;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set the Software NSS Signal Low
|
||||
|
||||
In slave mode, and only when software slave management is used, this replaces
|
||||
the NSS signal with a slave select disable signal.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_nss_low(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) &= ~SPI_CR1_SSI;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set to Send LSB First
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_send_lsb_first(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) |= SPI_CR1_LSBFIRST;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set to Send MSB First
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_send_msb_first(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) &= ~SPI_CR1_LSBFIRST;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set the Baudrate Prescaler
|
||||
|
||||
@todo Why is this specification different to the spi_init_master baudrate
|
||||
values?
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
@param[in] baudrate Unsigned int8. Baudrate prescale value @ref spi_br_pre.
|
||||
*/
|
||||
|
||||
void spi_set_baudrate_prescaler(uint32_t spi, uint8_t baudrate)
|
||||
{
|
||||
uint32_t reg32;
|
||||
|
||||
if (baudrate > 7) {
|
||||
return;
|
||||
}
|
||||
|
||||
reg32 = (SPI_CR1(spi) & 0xffc7); /* Clear bits [5:3]. */
|
||||
reg32 |= (baudrate << 3);
|
||||
SPI_CR1(spi) = reg32;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set to Master Mode
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_master_mode(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) |= SPI_CR1_MSTR;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set to Slave Mode
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_slave_mode(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) &= ~SPI_CR1_MSTR;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set the Clock Polarity to High when Idle
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_clock_polarity_1(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) |= SPI_CR1_CPOL;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set the Clock Polarity to Low when Idle
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_clock_polarity_0(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) &= ~SPI_CR1_CPOL;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set the Clock Phase to Capture on Trailing Edge
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_clock_phase_1(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) |= SPI_CR1_CPHA;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set the Clock Phase to Capture on Leading Edge
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_clock_phase_0(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) &= ~SPI_CR1_CPHA;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Enable the Transmit Buffer Empty Interrupt
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_enable_tx_buffer_empty_interrupt(uint32_t spi)
|
||||
{
|
||||
SPI_CR2(spi) |= SPI_CR2_TXEIE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Disable the Transmit Buffer Empty Interrupt
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_disable_tx_buffer_empty_interrupt(uint32_t spi)
|
||||
{
|
||||
SPI_CR2(spi) &= ~SPI_CR2_TXEIE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Enable the Receive Buffer Ready Interrupt
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_enable_rx_buffer_not_empty_interrupt(uint32_t spi)
|
||||
{
|
||||
SPI_CR2(spi) |= SPI_CR2_RXNEIE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Disable the Receive Buffer Ready Interrupt
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_disable_rx_buffer_not_empty_interrupt(uint32_t spi)
|
||||
{
|
||||
SPI_CR2(spi) &= ~SPI_CR2_RXNEIE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Enable the Error Interrupt
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_enable_error_interrupt(uint32_t spi)
|
||||
{
|
||||
SPI_CR2(spi) |= SPI_CR2_ERRIE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Disable the Error Interrupt
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_disable_error_interrupt(uint32_t spi)
|
||||
{
|
||||
SPI_CR2(spi) &= ~SPI_CR2_ERRIE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set the NSS Pin as an Output
|
||||
|
||||
Normally used in master mode to allows the master to place all devices on the
|
||||
SPI bus into slave mode. Multimaster mode is not possible.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_enable_ss_output(uint32_t spi)
|
||||
{
|
||||
SPI_CR2(spi) |= SPI_CR2_SSOE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set the NSS Pin as an Input
|
||||
|
||||
In master mode this allows the master to sense the presence of other masters. If
|
||||
NSS is then pulled low the master is placed into slave mode. In slave mode NSS
|
||||
becomes a slave enable.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_disable_ss_output(uint32_t spi)
|
||||
{
|
||||
SPI_CR2(spi) &= ~SPI_CR2_SSOE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Enable Transmit Transfers via DMA
|
||||
|
||||
This allows transmissions to proceed unattended using DMA to move data to the
|
||||
transmit buffer as it becomes available. The DMA channels provided for each
|
||||
SPI peripheral are given in the Technical Manual DMA section.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_enable_tx_dma(uint32_t spi)
|
||||
{
|
||||
SPI_CR2(spi) |= SPI_CR2_TXDMAEN;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Disable Transmit Transfers via DMA
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_disable_tx_dma(uint32_t spi)
|
||||
{
|
||||
SPI_CR2(spi) &= ~SPI_CR2_TXDMAEN;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Enable Receive Transfers via DMA
|
||||
|
||||
This allows received data streams to proceed unattended using DMA to move data
|
||||
from the receive buffer as data becomes available. The DMA channels provided
|
||||
for each SPI peripheral are given in the Technical Manual DMA section.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_enable_rx_dma(uint32_t spi)
|
||||
{
|
||||
SPI_CR2(spi) |= SPI_CR2_RXDMAEN;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Disable Receive Transfers via DMA
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_disable_rx_dma(uint32_t spi)
|
||||
{
|
||||
SPI_CR2(spi) &= ~SPI_CR2_RXDMAEN;
|
||||
}
|
||||
|
||||
/**@}*/
|
@ -0,0 +1,137 @@
|
||||
/** @addtogroup spi_file
|
||||
|
||||
@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: 1Mbps, positive clock polarity, leading edge trigger, 8-bit words,
|
||||
LSB first.
|
||||
@code
|
||||
spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
|
||||
SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT,
|
||||
SPI_CR1_LSBFIRST);
|
||||
spi_write(SPI1, 0x55); // 8-bit write
|
||||
spi_write(SPI1, 0xaa88); // 16-bit write
|
||||
reg8 = spi_read(SPI1); // 8-bit read
|
||||
reg16 = spi_read(SPI1); // 16-bit read
|
||||
@endcode
|
||||
|
||||
@todo need additional functions to aid ISRs in retrieving status
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libopencm3/stm32/spi.h>
|
||||
#include <libopencm3/stm32/rcc.h>
|
||||
|
||||
/*
|
||||
* SPI and I2S code.
|
||||
*
|
||||
* Examples:
|
||||
* spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
|
||||
* SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT,
|
||||
* SPI_CR1_LSBFIRST);
|
||||
* spi_write(SPI1, 0x55); // 8-bit write
|
||||
* spi_write(SPI1, 0xaa88); // 16-bit write
|
||||
* reg8 = spi_read(SPI1); // 8-bit read
|
||||
* reg16 = spi_read(SPI1); // 16-bit read
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Configure the SPI as Master.
|
||||
|
||||
The SPI peripheral is configured as a master with communication parameters
|
||||
baudrate, data format 8/16 bits, frame format lsb/msb first, clock polarity
|
||||
and phase. The SPI enable, CRC enable and CRC next controls are not affected.
|
||||
These must be controlled separately.
|
||||
|
||||
@todo NSS pin handling.
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
@param[in] br Unsigned int32. Baudrate @ref spi_baudrate.
|
||||
@param[in] cpol Unsigned int32. Clock polarity @ref spi_cpol.
|
||||
@param[in] cpha Unsigned int32. Clock Phase @ref spi_cpha.
|
||||
@param[in] dff Unsigned int32. Data frame format 8/16 bits @ref spi_dff.
|
||||
@param[in] lsbfirst Unsigned int32. Frame format lsb/msb first @ref
|
||||
spi_lsbfirst.
|
||||
@returns int. Error code.
|
||||
*/
|
||||
|
||||
int spi_init_master(uint32_t spi, uint32_t br, uint32_t cpol, uint32_t cpha,
|
||||
uint32_t dff, uint32_t lsbfirst)
|
||||
{
|
||||
uint32_t reg32 = SPI_CR1(spi);
|
||||
|
||||
/* Reset all bits omitting SPE, CRCEN and CRCNEXT bits. */
|
||||
reg32 &= SPI_CR1_SPE | SPI_CR1_CRCEN | SPI_CR1_CRCNEXT;
|
||||
|
||||
reg32 |= SPI_CR1_MSTR; /* Configure SPI as master. */
|
||||
|
||||
reg32 |= br; /* Set baud rate bits. */
|
||||
reg32 |= cpol; /* Set CPOL value. */
|
||||
reg32 |= cpha; /* Set CPHA value. */
|
||||
reg32 |= dff; /* Set data format (8 or 16 bits). */
|
||||
reg32 |= lsbfirst; /* Set frame format (LSB- or MSB-first). */
|
||||
|
||||
/* TODO: NSS pin handling. */
|
||||
|
||||
SPI_CR1(spi) = reg32;
|
||||
|
||||
return 0; /* TODO */
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set Data Frame Format to 8 bits
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_dff_8bit(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) &= ~SPI_CR1_DFF;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief SPI Set Data Frame Format to 16 bits
|
||||
|
||||
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
|
||||
*/
|
||||
|
||||
void spi_set_dff_16bit(uint32_t spi)
|
||||
{
|
||||
SPI_CR1(spi) |= SPI_CR1_DFF;
|
||||
}
|
||||
|
||||
/**@}*/
|
File diff suppressed because it is too large
Load Diff
@ -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) &= ~(0x6 << (ic * 4));
|
||||
switch (pol) {
|
||||
case TIM_IC_RISING: /* 00 */
|
||||
break;
|
||||
case TIM_IC_BOTH: /* 11 */
|
||||
TIM_CCER(timer_peripheral) |= (0x6 << (ic * 4));
|
||||
break;
|
||||
case TIM_IC_FALLING: /* 01 */
|
||||
TIM_CCER(timer_peripheral) |= (0x2 << (ic * 4));
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
|
@ -0,0 +1,53 @@
|
||||
/** @addtogroup timer_file
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2010 Edward Cheeseman <evbuilder@users.sourceforge.org>
|
||||
* Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
#include <libopencm3/stm32/timer.h>
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Set Timer Option
|
||||
|
||||
Set timer options register on TIM2 or TIM5, used for trigger remapping on TIM2,
|
||||
and similarly for TIM5 for oscillator calibration purposes.
|
||||
|
||||
@param[in] timer_peripheral Unsigned int32. Timer register address base
|
||||
@returns Unsigned int32. Option flags TIM2: @ref tim2_opt_trigger_remap, TIM5:
|
||||
@ref tim5_opt_trigger_remap.
|
||||
*/
|
||||
|
||||
void timer_set_option(uint32_t timer_peripheral, uint32_t option)
|
||||
{
|
||||
if (timer_peripheral == TIM2) {
|
||||
TIM_OR(timer_peripheral) &= ~TIM2_OR_ITR1_RMP_MASK;
|
||||
TIM_OR(timer_peripheral) |= option;
|
||||
} else if (timer_peripheral == TIM5) {
|
||||
TIM_OR(timer_peripheral) &= ~TIM5_OR_TI4_RMP_MASK;
|
||||
TIM_OR(timer_peripheral) |= option;
|
||||
}
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
|
@ -0,0 +1,367 @@
|
||||
/** @addtogroup usart_file
|
||||
|
||||
@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).
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
@param[in] baud unsigned 32 bit. Baud rate specified in Hz.
|
||||
*/
|
||||
|
||||
void usart_set_baudrate(uint32_t usart, uint32_t baud)
|
||||
{
|
||||
uint32_t clock = rcc_ppre1_frequency;
|
||||
|
||||
#if defined STM32F2 || defined STM32F4
|
||||
if ((usart == USART1) ||
|
||||
(usart == USART6)) {
|
||||
clock = rcc_ppre2_frequency;
|
||||
}
|
||||
#else
|
||||
if (usart == USART1) {
|
||||
clock = rcc_ppre2_frequency;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Yes it is as simple as that. The reference manual is
|
||||
* talking about fractional calculation but it seems to be only
|
||||
* marketting babble to sound awesome. It is nothing else but a
|
||||
* simple divider to generate the correct baudrate.
|
||||
*
|
||||
* Note: We round() the value rather than floor()ing it, for more
|
||||
* accurate divisor selection.
|
||||
*/
|
||||
USART_BRR(usart) = ((2 * clock) + baud) / (2 * baud);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Set Word Length.
|
||||
|
||||
The word length is set to 8 or 9 bits. Note that the last bit will be a parity
|
||||
bit if parity is enabled, in which case the data length will be 7 or 8 bits
|
||||
respectively.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
@param[in] bits unsigned 32 bit. Word length in bits 8 or 9.
|
||||
*/
|
||||
|
||||
void usart_set_databits(uint32_t usart, uint32_t bits)
|
||||
{
|
||||
if (bits == 8) {
|
||||
USART_CR1(usart) &= ~USART_CR1_M; /* 8 data bits */
|
||||
} else {
|
||||
USART_CR1(usart) |= USART_CR1_M; /* 9 data bits */
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Set Stop Bit(s).
|
||||
|
||||
The stop bits are specified as 0.5, 1, 1.5 or 2.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
@param[in] stopbits unsigned 32 bit. Stop bits @ref usart_cr2_stopbits.
|
||||
*/
|
||||
|
||||
void usart_set_stopbits(uint32_t usart, uint32_t stopbits)
|
||||
{
|
||||
uint32_t reg32;
|
||||
|
||||
reg32 = USART_CR2(usart);
|
||||
reg32 = (reg32 & ~USART_CR2_STOPBITS_MASK) | stopbits;
|
||||
USART_CR2(usart) = reg32;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Set Parity.
|
||||
|
||||
The parity bit can be selected as none, even or odd.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
@param[in] parity unsigned 32 bit. Parity @ref usart_cr1_parity.
|
||||
*/
|
||||
|
||||
void usart_set_parity(uint32_t usart, uint32_t parity)
|
||||
{
|
||||
uint32_t reg32;
|
||||
|
||||
reg32 = USART_CR1(usart);
|
||||
reg32 = (reg32 & ~USART_PARITY_MASK) | parity;
|
||||
USART_CR1(usart) = reg32;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Set Rx/Tx Mode.
|
||||
|
||||
The mode can be selected as Rx only, Tx only or Rx+Tx.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
@param[in] mode unsigned 32 bit. Mode @ref usart_cr1_mode.
|
||||
*/
|
||||
|
||||
void usart_set_mode(uint32_t usart, uint32_t mode)
|
||||
{
|
||||
uint32_t reg32;
|
||||
|
||||
reg32 = USART_CR1(usart);
|
||||
reg32 = (reg32 & ~USART_MODE_MASK) | mode;
|
||||
USART_CR1(usart) = reg32;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Set Hardware Flow Control.
|
||||
|
||||
The flow control bit can be selected as none, RTS, CTS or RTS+CTS.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
@param[in] flowcontrol unsigned 32 bit. Flowcontrol @ref usart_cr3_flowcontrol.
|
||||
*/
|
||||
|
||||
void usart_set_flow_control(uint32_t usart, uint32_t flowcontrol)
|
||||
{
|
||||
uint32_t reg32;
|
||||
|
||||
reg32 = USART_CR3(usart);
|
||||
reg32 = (reg32 & ~USART_FLOWCONTROL_MASK) | flowcontrol;
|
||||
USART_CR3(usart) = reg32;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Enable.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
*/
|
||||
|
||||
void usart_enable(uint32_t usart)
|
||||
{
|
||||
USART_CR1(usart) |= USART_CR1_UE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Disable.
|
||||
|
||||
At the end of the current frame, the USART is disabled to reduce power.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
*/
|
||||
|
||||
void usart_disable(uint32_t usart)
|
||||
{
|
||||
USART_CR1(usart) &= ~USART_CR1_UE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Send Data Word with Blocking
|
||||
|
||||
Blocks until the transmit data buffer becomes empty then writes the next data
|
||||
word for transmission.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
@param[in] data unsigned 16 bit.
|
||||
*/
|
||||
|
||||
void usart_send_blocking(uint32_t usart, uint16_t data)
|
||||
{
|
||||
usart_wait_send_ready(usart);
|
||||
usart_send(usart, data);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Read a Received Data Word with Blocking.
|
||||
|
||||
Wait until a data word has been received then return the word.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
@returns unsigned 16 bit data word.
|
||||
*/
|
||||
|
||||
uint16_t usart_recv_blocking(uint32_t usart)
|
||||
{
|
||||
usart_wait_recv_ready(usart);
|
||||
|
||||
return usart_recv(usart);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Receiver DMA Enable.
|
||||
|
||||
DMA is available on:
|
||||
@li USART1 Rx DMA1 channel 5.
|
||||
@li USART2 Rx DMA1 channel 6.
|
||||
@li USART3 Rx DMA1 channel 3.
|
||||
@li UART4 Rx DMA2 channel 3.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
*/
|
||||
|
||||
void usart_enable_rx_dma(uint32_t usart)
|
||||
{
|
||||
USART_CR3(usart) |= USART_CR3_DMAR;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Receiver DMA Disable.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
*/
|
||||
|
||||
void usart_disable_rx_dma(uint32_t usart)
|
||||
{
|
||||
USART_CR3(usart) &= ~USART_CR3_DMAR;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Transmitter DMA Enable.
|
||||
|
||||
DMA is available on:
|
||||
@li USART1 Tx DMA1 channel 4.
|
||||
@li USART2 Tx DMA1 channel 7.
|
||||
@li USART3 Tx DMA1 channel 2.
|
||||
@li UART4 Tx DMA2 channel 5.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
*/
|
||||
|
||||
void usart_enable_tx_dma(uint32_t usart)
|
||||
{
|
||||
USART_CR3(usart) |= USART_CR3_DMAT;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Transmitter DMA Disable.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
*/
|
||||
|
||||
void usart_disable_tx_dma(uint32_t usart)
|
||||
{
|
||||
USART_CR3(usart) &= ~USART_CR3_DMAT;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Receiver Interrupt Enable.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
*/
|
||||
|
||||
void usart_enable_rx_interrupt(uint32_t usart)
|
||||
{
|
||||
USART_CR1(usart) |= USART_CR1_RXNEIE;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Receiver Interrupt Disable.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
*/
|
||||
|
||||
void usart_disable_rx_interrupt(uint32_t usart)
|
||||
{
|
||||
USART_CR1(usart) &= ~USART_CR1_RXNEIE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Transmitter Interrupt Enable.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
*/
|
||||
|
||||
void usart_enable_tx_interrupt(uint32_t usart)
|
||||
{
|
||||
USART_CR1(usart) |= USART_CR1_TXEIE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Transmitter Interrupt Disable.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
*/
|
||||
|
||||
void usart_disable_tx_interrupt(uint32_t usart)
|
||||
{
|
||||
USART_CR1(usart) &= ~USART_CR1_TXEIE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Error Interrupt Enable.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
*/
|
||||
|
||||
void usart_enable_error_interrupt(uint32_t usart)
|
||||
{
|
||||
USART_CR3(usart) |= USART_CR3_EIE;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Error Interrupt Disable.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
*/
|
||||
|
||||
void usart_disable_error_interrupt(uint32_t usart)
|
||||
{
|
||||
USART_CR3(usart) &= ~USART_CR3_EIE;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
@ -0,0 +1,143 @@
|
||||
/** @addtogroup usart_file
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief USART Return Interrupt Source.
|
||||
|
||||
Returns true if the specified interrupt flag (IDLE, RXNE, TC, TXE or OE) was
|
||||
set and the interrupt was enabled. If the specified flag is not an interrupt
|
||||
flag, the function returns false.
|
||||
|
||||
@todo These are the most important interrupts likely to be used. Others
|
||||
relating to LIN break, and error conditions in multibuffer communication, need
|
||||
to be added for completeness.
|
||||
|
||||
@param[in] usart unsigned 32 bit. USART block register address base @ref
|
||||
usart_reg_base
|
||||
@param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags.
|
||||
@returns boolean: flag and interrupt enable both set.
|
||||
*/
|
||||
|
||||
bool usart_get_interrupt_source(uint32_t usart, uint32_t flag)
|
||||
{
|
||||
uint32_t flag_set = (USART_SR(usart) & flag);
|
||||
/* IDLE, RXNE, TC, TXE interrupts */
|
||||
if ((flag >= USART_SR_IDLE) && (flag <= USART_SR_TXE)) {
|
||||
return ((flag_set & USART_CR1(usart)) != 0);
|
||||
/* Overrun error */
|
||||
} else if (flag == USART_SR_ORE) {
|
||||
return flag_set && (USART_CR3(usart) & USART_CR3_CTSIE);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**@}*/
|
Reference in New Issue
Block a user