init proj

This commit is contained in:
2025-06-24 19:06:17 +03:00
parent 295c52a068
commit 93ab91eb16
117 changed files with 113513 additions and 0 deletions

View File

@@ -0,0 +1,607 @@
/**
******************************************************************************
* @file stm32f1xx_hal.c
* @author MCD Application Team
* @brief HAL module driver.
* This is the common part of the HAL initialization
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
The common HAL driver contains a set of generic and common APIs that can be
used by the PPP peripheral drivers and the user to start using the HAL.
[..]
The HAL contains two APIs' categories:
(+) Common HAL APIs
(+) Services HAL APIs
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup HAL HAL
* @brief HAL module driver.
* @{
*/
#ifdef HAL_MODULE_ENABLED
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup HAL_Private_Constants HAL Private Constants
* @{
*/
/**
* @brief STM32F1xx HAL Driver version number
*/
#define __STM32F1xx_HAL_VERSION_MAIN (0x01U) /*!< [31:24] main version */
#define __STM32F1xx_HAL_VERSION_SUB1 (0x01U) /*!< [23:16] sub1 version */
#define __STM32F1xx_HAL_VERSION_SUB2 (0x0AU) /*!< [15:8] sub2 version */
#define __STM32F1xx_HAL_VERSION_RC (0x00U) /*!< [7:0] release candidate */
#define __STM32F1xx_HAL_VERSION ((__STM32F1xx_HAL_VERSION_MAIN << 24)\
|(__STM32F1xx_HAL_VERSION_SUB1 << 16)\
|(__STM32F1xx_HAL_VERSION_SUB2 << 8 )\
|(__STM32F1xx_HAL_VERSION_RC))
#define IDCODE_DEVID_MASK 0x00000FFFU
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup HAL_Private_Variables HAL Private Variables
* @{
*/
__IO uint32_t uwTick;
uint32_t uwTickPrio = (1UL << __NVIC_PRIO_BITS); /* Invalid PRIO */
HAL_TickFreqTypeDef uwTickFreq = HAL_TICK_FREQ_DEFAULT; /* 1KHz */
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions ---------------------------------------------------------*/
/** @defgroup HAL_Exported_Functions HAL Exported Functions
* @{
*/
/** @defgroup HAL_Exported_Functions_Group1 Initialization and de-initialization Functions
* @brief Initialization and de-initialization functions
*
@verbatim
===============================================================================
##### Initialization and de-initialization functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Initializes the Flash interface, the NVIC allocation and initial clock
configuration. It initializes the systick also when timeout is needed
and the backup domain when enabled.
(+) de-Initializes common part of the HAL.
(+) Configure The time base source to have 1ms time base with a dedicated
Tick interrupt priority.
(++) SysTick timer is used by default as source of time base, but user
can eventually implement his proper time base source (a general purpose
timer for example or other time source), keeping in mind that Time base
duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and
handled in milliseconds basis.
(++) Time base configuration function (HAL_InitTick ()) is called automatically
at the beginning of the program after reset by HAL_Init() or at any time
when clock is configured, by HAL_RCC_ClockConfig().
(++) Source of time base is configured to generate interrupts at regular
time intervals. Care must be taken if HAL_Delay() is called from a
peripheral ISR process, the Tick interrupt line must have higher priority
(numerically lower) than the peripheral interrupt. Otherwise the caller
ISR process will be blocked.
(++) functions affecting time base configurations are declared as __weak
to make override possible in case of other implementations in user file.
@endverbatim
* @{
*/
/**
* @brief This function is used to initialize the HAL Library; it must be the first
* instruction to be executed in the main program (before to call any other
* HAL function), it performs the following:
* Configure the Flash prefetch.
* Configures the SysTick to generate an interrupt each 1 millisecond,
* which is clocked by the HSI (at this stage, the clock is not yet
* configured and thus the system is running from the internal HSI at 16 MHz).
* Set NVIC Group Priority to 4.
* Calls the HAL_MspInit() callback function defined in user file
* "stm32f1xx_hal_msp.c" to do the global low level hardware initialization
*
* @note SysTick is used as time base for the HAL_Delay() function, the application
* need to ensure that the SysTick time base is always set to 1 millisecond
* to have correct HAL operation.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_Init(void)
{
/* Configure Flash prefetch */
#if (PREFETCH_ENABLE != 0)
#if defined(STM32F101x6) || defined(STM32F101xB) || defined(STM32F101xE) || defined(STM32F101xG) || \
defined(STM32F102x6) || defined(STM32F102xB) || \
defined(STM32F103x6) || defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG) || \
defined(STM32F105xC) || defined(STM32F107xC)
/* Prefetch buffer is not available on value line devices */
__HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif
#endif /* PREFETCH_ENABLE */
/* Set Interrupt Group Priority */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
/* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
HAL_InitTick(TICK_INT_PRIORITY);
/* Init the low level hardware */
HAL_MspInit();
/* Return function status */
return HAL_OK;
}
/**
* @brief This function de-Initializes common part of the HAL and stops the systick.
* of time base.
* @note This function is optional.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DeInit(void)
{
/* Reset of all peripherals */
__HAL_RCC_APB1_FORCE_RESET();
__HAL_RCC_APB1_RELEASE_RESET();
__HAL_RCC_APB2_FORCE_RESET();
__HAL_RCC_APB2_RELEASE_RESET();
#if defined(STM32F105xC) || defined(STM32F107xC)
__HAL_RCC_AHB_FORCE_RESET();
__HAL_RCC_AHB_RELEASE_RESET();
#endif
/* De-Init the low level hardware */
HAL_MspDeInit();
/* Return function status */
return HAL_OK;
}
/**
* @brief Initialize the MSP.
* @retval None
*/
__weak void HAL_MspInit(void)
{
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_MspInit could be implemented in the user file
*/
}
/**
* @brief DeInitializes the MSP.
* @retval None
*/
__weak void HAL_MspDeInit(void)
{
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_MspDeInit could be implemented in the user file
*/
}
/**
* @brief This function configures the source of the time base.
* The time source is configured to have 1ms time base with a dedicated
* Tick interrupt priority.
* @note This function is called automatically at the beginning of program after
* reset by HAL_Init() or at any time when clock is reconfigured by HAL_RCC_ClockConfig().
* @note In the default implementation, SysTick timer is the source of time base.
* It is used to generate interrupts at regular time intervals.
* Care must be taken if HAL_Delay() is called from a peripheral ISR process,
* The SysTick interrupt must have higher priority (numerically lower)
* than the peripheral interrupt. Otherwise the caller ISR process will be blocked.
* The function is declared as __weak to be overwritten in case of other
* implementation in user file.
* @param TickPriority Tick interrupt priority.
* @retval HAL status
*/
__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
/* Configure the SysTick to have interrupt in 1ms time basis*/
if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)
{
return HAL_ERROR;
}
/* Configure the SysTick IRQ priority */
if (TickPriority < (1UL << __NVIC_PRIO_BITS))
{
HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
uwTickPrio = TickPriority;
}
else
{
return HAL_ERROR;
}
/* Return function status */
return HAL_OK;
}
/**
* @}
*/
/** @defgroup HAL_Exported_Functions_Group2 HAL Control functions
* @brief HAL Control functions
*
@verbatim
===============================================================================
##### HAL Control functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Provide a tick value in millisecond
(+) Provide a blocking delay in millisecond
(+) Suspend the time base source interrupt
(+) Resume the time base source interrupt
(+) Get the HAL API driver version
(+) Get the device identifier
(+) Get the device revision identifier
(+) Enable/Disable Debug module during SLEEP mode
(+) Enable/Disable Debug module during STOP mode
(+) Enable/Disable Debug module during STANDBY mode
@endverbatim
* @{
*/
/**
* @brief This function is called to increment a global variable "uwTick"
* used as application time base.
* @note In the default implementation, this variable is incremented each 1ms
* in SysTick ISR.
* @note This function is declared as __weak to be overwritten in case of other
* implementations in user file.
* @retval None
*/
__weak void HAL_IncTick(void)
{
uwTick += uwTickFreq;
}
/**
* @brief Provides a tick value in millisecond.
* @note This function is declared as __weak to be overwritten in case of other
* implementations in user file.
* @retval tick value
*/
__weak uint32_t HAL_GetTick(void)
{
return uwTick;
}
/**
* @brief This function returns a tick priority.
* @retval tick priority
*/
uint32_t HAL_GetTickPrio(void)
{
return uwTickPrio;
}
/**
* @brief Set new tick Freq.
* @retval status
*/
HAL_StatusTypeDef HAL_SetTickFreq(HAL_TickFreqTypeDef Freq)
{
HAL_StatusTypeDef status = HAL_OK;
HAL_TickFreqTypeDef prevTickFreq;
assert_param(IS_TICKFREQ(Freq));
if (uwTickFreq != Freq)
{
/* Back up uwTickFreq frequency */
prevTickFreq = uwTickFreq;
/* Update uwTickFreq global variable used by HAL_InitTick() */
uwTickFreq = Freq;
/* Apply the new tick Freq */
status = HAL_InitTick(uwTickPrio);
if (status != HAL_OK)
{
/* Restore previous tick frequency */
uwTickFreq = prevTickFreq;
}
}
return status;
}
/**
* @brief Return tick frequency.
* @retval Tick frequency.
* Value of @ref HAL_TickFreqTypeDef.
*/
HAL_TickFreqTypeDef HAL_GetTickFreq(void)
{
return uwTickFreq;
}
/**
* @brief This function provides minimum delay (in milliseconds) based
* on variable incremented.
* @note In the default implementation , SysTick timer is the source of time base.
* It is used to generate interrupts at regular time intervals where uwTick
* is incremented.
* @note This function is declared as __weak to be overwritten in case of other
* implementations in user file.
* @param Delay specifies the delay time length, in milliseconds.
* @retval None
*/
__weak void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick();
uint32_t wait = Delay;
/* Add a freq to guarantee minimum wait */
if (wait < HAL_MAX_DELAY)
{
wait += (uint32_t)(uwTickFreq);
}
while ((HAL_GetTick() - tickstart) < wait)
{
}
}
/**
* @brief Suspend Tick increment.
* @note In the default implementation , SysTick timer is the source of time base. It is
* used to generate interrupts at regular time intervals. Once HAL_SuspendTick()
* is called, the SysTick interrupt will be disabled and so Tick increment
* is suspended.
* @note This function is declared as __weak to be overwritten in case of other
* implementations in user file.
* @retval None
*/
__weak void HAL_SuspendTick(void)
{
/* Disable SysTick Interrupt */
CLEAR_BIT(SysTick->CTRL, SysTick_CTRL_TICKINT_Msk);
}
/**
* @brief Resume Tick increment.
* @note In the default implementation , SysTick timer is the source of time base. It is
* used to generate interrupts at regular time intervals. Once HAL_ResumeTick()
* is called, the SysTick interrupt will be enabled and so Tick increment
* is resumed.
* @note This function is declared as __weak to be overwritten in case of other
* implementations in user file.
* @retval None
*/
__weak void HAL_ResumeTick(void)
{
/* Enable SysTick Interrupt */
SET_BIT(SysTick->CTRL, SysTick_CTRL_TICKINT_Msk);
}
/**
* @brief Returns the HAL revision
* @retval version 0xXYZR (8bits for each decimal, R for RC)
*/
uint32_t HAL_GetHalVersion(void)
{
return __STM32F1xx_HAL_VERSION;
}
/**
* @brief Returns the device revision identifier.
* Note: On devices STM32F10xx8 and STM32F10xxB,
* STM32F101xC/D/E and STM32F103xC/D/E,
* STM32F101xF/G and STM32F103xF/G
* STM32F10xx4 and STM32F10xx6
* Debug registers DBGMCU_IDCODE and DBGMCU_CR are accessible only in
* debug mode (not accessible by the user software in normal mode).
* Refer to errata sheet of these devices for more details.
* @retval Device revision identifier
*/
uint32_t HAL_GetREVID(void)
{
return ((DBGMCU->IDCODE) >> DBGMCU_IDCODE_REV_ID_Pos);
}
/**
* @brief Returns the device identifier.
* Note: On devices STM32F10xx8 and STM32F10xxB,
* STM32F101xC/D/E and STM32F103xC/D/E,
* STM32F101xF/G and STM32F103xF/G
* STM32F10xx4 and STM32F10xx6
* Debug registers DBGMCU_IDCODE and DBGMCU_CR are accessible only in
* debug mode (not accessible by the user software in normal mode).
* Refer to errata sheet of these devices for more details.
* @retval Device identifier
*/
uint32_t HAL_GetDEVID(void)
{
return ((DBGMCU->IDCODE) & IDCODE_DEVID_MASK);
}
/**
* @brief Returns first word of the unique device identifier (UID based on 96 bits)
* @retval Device identifier
*/
uint32_t HAL_GetUIDw0(void)
{
return(READ_REG(*((uint32_t *)UID_BASE)));
}
/**
* @brief Returns second word of the unique device identifier (UID based on 96 bits)
* @retval Device identifier
*/
uint32_t HAL_GetUIDw1(void)
{
return(READ_REG(*((uint32_t *)(UID_BASE + 4U))));
}
/**
* @brief Returns third word of the unique device identifier (UID based on 96 bits)
* @retval Device identifier
*/
uint32_t HAL_GetUIDw2(void)
{
return(READ_REG(*((uint32_t *)(UID_BASE + 8U))));
}
/**
* @brief Enable the Debug Module during SLEEP mode
* @retval None
*/
void HAL_DBGMCU_EnableDBGSleepMode(void)
{
SET_BIT(DBGMCU->CR, DBGMCU_CR_DBG_SLEEP);
}
/**
* @brief Disable the Debug Module during SLEEP mode
* Note: On devices STM32F10xx8 and STM32F10xxB,
* STM32F101xC/D/E and STM32F103xC/D/E,
* STM32F101xF/G and STM32F103xF/G
* STM32F10xx4 and STM32F10xx6
* Debug registers DBGMCU_IDCODE and DBGMCU_CR are accessible only in
* debug mode (not accessible by the user software in normal mode).
* Refer to errata sheet of these devices for more details.
* @retval None
*/
void HAL_DBGMCU_DisableDBGSleepMode(void)
{
CLEAR_BIT(DBGMCU->CR, DBGMCU_CR_DBG_SLEEP);
}
/**
* @brief Enable the Debug Module during STOP mode
* Note: On devices STM32F10xx8 and STM32F10xxB,
* STM32F101xC/D/E and STM32F103xC/D/E,
* STM32F101xF/G and STM32F103xF/G
* STM32F10xx4 and STM32F10xx6
* Debug registers DBGMCU_IDCODE and DBGMCU_CR are accessible only in
* debug mode (not accessible by the user software in normal mode).
* Refer to errata sheet of these devices for more details.
* Note: On all STM32F1 devices:
* If the system tick timer interrupt is enabled during the Stop mode
* debug (DBG_STOP bit set in the DBGMCU_CR register ), it will wakeup
* the system from Stop mode.
* Workaround: To debug the Stop mode, disable the system tick timer
* interrupt.
* Refer to errata sheet of these devices for more details.
* Note: On all STM32F1 devices:
* If the system tick timer interrupt is enabled during the Stop mode
* debug (DBG_STOP bit set in the DBGMCU_CR register ), it will wakeup
* the system from Stop mode.
* Workaround: To debug the Stop mode, disable the system tick timer
* interrupt.
* Refer to errata sheet of these devices for more details.
* @retval None
*/
void HAL_DBGMCU_EnableDBGStopMode(void)
{
SET_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STOP);
}
/**
* @brief Disable the Debug Module during STOP mode
* Note: On devices STM32F10xx8 and STM32F10xxB,
* STM32F101xC/D/E and STM32F103xC/D/E,
* STM32F101xF/G and STM32F103xF/G
* STM32F10xx4 and STM32F10xx6
* Debug registers DBGMCU_IDCODE and DBGMCU_CR are accessible only in
* debug mode (not accessible by the user software in normal mode).
* Refer to errata sheet of these devices for more details.
* @retval None
*/
void HAL_DBGMCU_DisableDBGStopMode(void)
{
CLEAR_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STOP);
}
/**
* @brief Enable the Debug Module during STANDBY mode
* Note: On devices STM32F10xx8 and STM32F10xxB,
* STM32F101xC/D/E and STM32F103xC/D/E,
* STM32F101xF/G and STM32F103xF/G
* STM32F10xx4 and STM32F10xx6
* Debug registers DBGMCU_IDCODE and DBGMCU_CR are accessible only in
* debug mode (not accessible by the user software in normal mode).
* Refer to errata sheet of these devices for more details.
* @retval None
*/
void HAL_DBGMCU_EnableDBGStandbyMode(void)
{
SET_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STANDBY);
}
/**
* @brief Disable the Debug Module during STANDBY mode
* Note: On devices STM32F10xx8 and STM32F10xxB,
* STM32F101xC/D/E and STM32F103xC/D/E,
* STM32F101xF/G and STM32F103xF/G
* STM32F10xx4 and STM32F10xx6
* Debug registers DBGMCU_IDCODE and DBGMCU_CR are accessible only in
* debug mode (not accessible by the user software in normal mode).
* Refer to errata sheet of these devices for more details.
* @retval None
*/
void HAL_DBGMCU_DisableDBGStandbyMode(void)
{
CLEAR_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STANDBY);
}
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,2428 @@
/**
******************************************************************************
* @file stm32f1xx_hal_adc.c
* @author MCD Application Team
* @brief This file provides firmware functions to manage the following
* functionalities of the Analog to Digital Convertor (ADC)
* peripheral:
* + Initialization and de-initialization functions
* + Peripheral Control functions
* + Peripheral State functions
* Other functions (extended functions) are available in file
* "stm32f1xx_hal_adc_ex.c".
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### ADC peripheral features #####
==============================================================================
[..]
(+) 12-bit resolution
(+) Interrupt generation at the end of regular conversion, end of injected
conversion, and in case of analog watchdog or overrun events.
(+) Single and continuous conversion modes.
(+) Scan mode for conversion of several channels sequentially.
(+) Data alignment with in-built data coherency.
(+) Programmable sampling time (channel wise)
(+) ADC conversion of regular group and injected group.
(+) External trigger (timer or EXTI)
for both regular and injected groups.
(+) DMA request generation for transfer of conversions data of regular group.
(+) Multimode Dual mode (available on devices with 2 ADCs or more).
(+) Configurable DMA data storage in Multimode Dual mode (available on devices
with 2 DCs or more).
(+) Configurable delay between conversions in Dual interleaved mode (available
on devices with 2 DCs or more).
(+) ADC calibration
(+) ADC supply requirements: 2.4 V to 3.6 V at full speed and down to 1.8 V at
slower speed.
(+) ADC input range: from Vref- (connected to Vssa) to Vref+ (connected to
Vdda or to an external voltage reference).
##### How to use this driver #####
==============================================================================
[..]
*** Configuration of top level parameters related to ADC ***
============================================================
[..]
(#) Enable the ADC interface
(++) As prerequisite, ADC clock must be configured at RCC top level.
Caution: On STM32F1, ADC clock frequency max is 14MHz (refer
to device datasheet).
Therefore, ADC clock prescaler must be configured in
function of ADC clock source frequency to remain below
this maximum frequency.
(++) One clock setting is mandatory:
ADC clock (core clock, also possibly conversion clock).
(+++) Example:
Into HAL_ADC_MspInit() (recommended code location) or with
other device clock parameters configuration:
(+++) RCC_PeriphCLKInitTypeDef PeriphClkInit;
(+++) __ADC1_CLK_ENABLE();
(+++) PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
(+++) PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV2;
(+++) HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
(#) ADC pins configuration
(++) Enable the clock for the ADC GPIOs
using macro __HAL_RCC_GPIOx_CLK_ENABLE()
(++) Configure these ADC pins in analog mode
using function HAL_GPIO_Init()
(#) Optionally, in case of usage of ADC with interruptions:
(++) Configure the NVIC for ADC
using function HAL_NVIC_EnableIRQ(ADCx_IRQn)
(++) Insert the ADC interruption handler function HAL_ADC_IRQHandler()
into the function of corresponding ADC interruption vector
ADCx_IRQHandler().
(#) Optionally, in case of usage of DMA:
(++) Configure the DMA (DMA channel, mode normal or circular, ...)
using function HAL_DMA_Init().
(++) Configure the NVIC for DMA
using function HAL_NVIC_EnableIRQ(DMAx_Channelx_IRQn)
(++) Insert the ADC interruption handler function HAL_ADC_IRQHandler()
into the function of corresponding DMA interruption vector
DMAx_Channelx_IRQHandler().
*** Configuration of ADC, groups regular/injected, channels parameters ***
==========================================================================
[..]
(#) Configure the ADC parameters (resolution, data alignment, ...)
and regular group parameters (conversion trigger, sequencer, ...)
using function HAL_ADC_Init().
(#) Configure the channels for regular group parameters (channel number,
channel rank into sequencer, ..., into regular group)
using function HAL_ADC_ConfigChannel().
(#) Optionally, configure the injected group parameters (conversion trigger,
sequencer, ..., of injected group)
and the channels for injected group parameters (channel number,
channel rank into sequencer, ..., into injected group)
using function HAL_ADCEx_InjectedConfigChannel().
(#) Optionally, configure the analog watchdog parameters (channels
monitored, thresholds, ...)
using function HAL_ADC_AnalogWDGConfig().
(#) Optionally, for devices with several ADC instances: configure the
multimode parameters
using function HAL_ADCEx_MultiModeConfigChannel().
*** Execution of ADC conversions ***
====================================
[..]
(#) Optionally, perform an automatic ADC calibration to improve the
conversion accuracy
using function HAL_ADCEx_Calibration_Start().
(#) ADC driver can be used among three modes: polling, interruption,
transfer by DMA.
(++) ADC conversion by polling:
(+++) Activate the ADC peripheral and start conversions
using function HAL_ADC_Start()
(+++) Wait for ADC conversion completion
using function HAL_ADC_PollForConversion()
(or for injected group: HAL_ADCEx_InjectedPollForConversion() )
(+++) Retrieve conversion results
using function HAL_ADC_GetValue()
(or for injected group: HAL_ADCEx_InjectedGetValue() )
(+++) Stop conversion and disable the ADC peripheral
using function HAL_ADC_Stop()
(++) ADC conversion by interruption:
(+++) Activate the ADC peripheral and start conversions
using function HAL_ADC_Start_IT()
(+++) Wait for ADC conversion completion by call of function
HAL_ADC_ConvCpltCallback()
(this function must be implemented in user program)
(or for injected group: HAL_ADCEx_InjectedConvCpltCallback() )
(+++) Retrieve conversion results
using function HAL_ADC_GetValue()
(or for injected group: HAL_ADCEx_InjectedGetValue() )
(+++) Stop conversion and disable the ADC peripheral
using function HAL_ADC_Stop_IT()
(++) ADC conversion with transfer by DMA:
(+++) Activate the ADC peripheral and start conversions
using function HAL_ADC_Start_DMA()
(+++) Wait for ADC conversion completion by call of function
HAL_ADC_ConvCpltCallback() or HAL_ADC_ConvHalfCpltCallback()
(these functions must be implemented in user program)
(+++) Conversion results are automatically transferred by DMA into
destination variable address.
(+++) Stop conversion and disable the ADC peripheral
using function HAL_ADC_Stop_DMA()
(++) For devices with several ADCs: ADC multimode conversion
with transfer by DMA:
(+++) Activate the ADC peripheral (slave) and start conversions
using function HAL_ADC_Start()
(+++) Activate the ADC peripheral (master) and start conversions
using function HAL_ADCEx_MultiModeStart_DMA()
(+++) Wait for ADC conversion completion by call of function
HAL_ADC_ConvCpltCallback() or HAL_ADC_ConvHalfCpltCallback()
(these functions must be implemented in user program)
(+++) Conversion results are automatically transferred by DMA into
destination variable address.
(+++) Stop conversion and disable the ADC peripheral (master)
using function HAL_ADCEx_MultiModeStop_DMA()
(+++) Stop conversion and disable the ADC peripheral (slave)
using function HAL_ADC_Stop_IT()
[..]
(@) Callback functions must be implemented in user program:
(+@) HAL_ADC_ErrorCallback()
(+@) HAL_ADC_LevelOutOfWindowCallback() (callback of analog watchdog)
(+@) HAL_ADC_ConvCpltCallback()
(+@) HAL_ADC_ConvHalfCpltCallback
(+@) HAL_ADCEx_InjectedConvCpltCallback()
*** Deinitialization of ADC ***
============================================================
[..]
(#) Disable the ADC interface
(++) ADC clock can be hard reset and disabled at RCC top level.
(++) Hard reset of ADC peripherals
using macro __ADCx_FORCE_RESET(), __ADCx_RELEASE_RESET().
(++) ADC clock disable
using the equivalent macro/functions as configuration step.
(+++) Example:
Into HAL_ADC_MspDeInit() (recommended code location) or with
other device clock parameters configuration:
(+++) PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC
(+++) PeriphClkInit.AdcClockSelection = RCC_ADCPLLCLK2_OFF
(+++) HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit)
(#) ADC pins configuration
(++) Disable the clock for the ADC GPIOs
using macro __HAL_RCC_GPIOx_CLK_DISABLE()
(#) Optionally, in case of usage of ADC with interruptions:
(++) Disable the NVIC for ADC
using function HAL_NVIC_EnableIRQ(ADCx_IRQn)
(#) Optionally, in case of usage of DMA:
(++) Deinitialize the DMA
using function HAL_DMA_Init().
(++) Disable the NVIC for DMA
using function HAL_NVIC_EnableIRQ(DMAx_Channelx_IRQn)
[..]
*** Callback registration ***
=============================================
[..]
The compilation flag USE_HAL_ADC_REGISTER_CALLBACKS, when set to 1,
allows the user to configure dynamically the driver callbacks.
Use Functions HAL_ADC_RegisterCallback()
to register an interrupt callback.
[..]
Function HAL_ADC_RegisterCallback() allows to register following callbacks:
(+) ConvCpltCallback : ADC conversion complete callback
(+) ConvHalfCpltCallback : ADC conversion DMA half-transfer callback
(+) LevelOutOfWindowCallback : ADC analog watchdog 1 callback
(+) ErrorCallback : ADC error callback
(+) InjectedConvCpltCallback : ADC group injected conversion complete callback
(+) MspInitCallback : ADC Msp Init callback
(+) MspDeInitCallback : ADC Msp DeInit callback
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
[..]
Use function HAL_ADC_UnRegisterCallback to reset a callback to the default
weak function.
[..]
HAL_ADC_UnRegisterCallback takes as parameters the HAL peripheral handle,
and the Callback ID.
This function allows to reset following callbacks:
(+) ConvCpltCallback : ADC conversion complete callback
(+) ConvHalfCpltCallback : ADC conversion DMA half-transfer callback
(+) LevelOutOfWindowCallback : ADC analog watchdog 1 callback
(+) ErrorCallback : ADC error callback
(+) InjectedConvCpltCallback : ADC group injected conversion complete callback
(+) MspInitCallback : ADC Msp Init callback
(+) MspDeInitCallback : ADC Msp DeInit callback
[..]
By default, after the HAL_ADC_Init() and when the state is HAL_ADC_STATE_RESET
all callbacks are set to the corresponding weak functions:
examples HAL_ADC_ConvCpltCallback(), HAL_ADC_ErrorCallback().
Exception done for MspInit and MspDeInit functions that are
reset to the legacy weak functions in the HAL_ADC_Init()/ HAL_ADC_DeInit() only when
these callbacks are null (not registered beforehand).
[..]
If MspInit or MspDeInit are not null, the HAL_ADC_Init()/ HAL_ADC_DeInit()
keep and use the user MspInit/MspDeInit callbacks (registered beforehand) whatever the state.
[..]
Callbacks can be registered/unregistered in HAL_ADC_STATE_READY state only.
Exception done MspInit/MspDeInit functions that can be registered/unregistered
in HAL_ADC_STATE_READY or HAL_ADC_STATE_RESET state,
thus registered (user) MspInit/DeInit callbacks can be used during the Init/DeInit.
[..]
Then, the user first registers the MspInit/MspDeInit user callbacks
using HAL_ADC_RegisterCallback() before calling HAL_ADC_DeInit()
or HAL_ADC_Init() function.
[..]
When the compilation flag USE_HAL_ADC_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registration feature is not available and all callbacks
are set to the corresponding weak functions.
@endverbatim
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup ADC ADC
* @brief ADC HAL module driver
* @{
*/
#ifdef HAL_ADC_MODULE_ENABLED
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup ADC_Private_Constants ADC Private Constants
* @{
*/
/* Timeout values for ADC enable and disable settling time. */
/* Values defined to be higher than worst cases: low clocks freq, */
/* maximum prescaler. */
/* Ex of profile low frequency : Clock source at 0.1 MHz, ADC clock */
/* prescaler 4, sampling time 12.5 ADC clock cycles, resolution 12 bits. */
/* Unit: ms */
#define ADC_ENABLE_TIMEOUT 2U
#define ADC_DISABLE_TIMEOUT 2U
/* Delay for ADC stabilization time. */
/* Maximum delay is 1us (refer to device datasheet, parameter tSTAB). */
/* Unit: us */
#define ADC_STAB_DELAY_US 1U
/* Delay for temperature sensor stabilization time. */
/* Maximum delay is 10us (refer to device datasheet, parameter tSTART). */
/* Unit: us */
#define ADC_TEMPSENSOR_DELAY_US 10U
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup ADC_Private_Functions ADC Private Functions
* @{
*/
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup ADC_Exported_Functions ADC Exported Functions
* @{
*/
/** @defgroup ADC_Exported_Functions_Group1 Initialization/de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
===============================================================================
##### Initialization and de-initialization functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Initialize and configure the ADC.
(+) De-initialize the ADC.
@endverbatim
* @{
*/
/**
* @brief Initializes the ADC peripheral and regular group according to
* parameters specified in structure "ADC_InitTypeDef".
* @note As prerequisite, ADC clock must be configured at RCC top level
* (clock source APB2).
* See commented example code below that can be copied and uncommented
* into HAL_ADC_MspInit().
* @note Possibility to update parameters on the fly:
* This function initializes the ADC MSP (HAL_ADC_MspInit()) only when
* coming from ADC state reset. Following calls to this function can
* be used to reconfigure some parameters of ADC_InitTypeDef
* structure on the fly, without modifying MSP configuration. If ADC
* MSP has to be modified again, HAL_ADC_DeInit() must be called
* before HAL_ADC_Init().
* The setting of these parameters is conditioned to ADC state.
* For parameters constraints, see comments of structure
* "ADC_InitTypeDef".
* @note This function configures the ADC within 2 scopes: scope of entire
* ADC and scope of regular group. For parameters details, see comments
* of structure "ADC_InitTypeDef".
* @param hadc: ADC handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ADC_Init(ADC_HandleTypeDef* hadc)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
uint32_t tmp_cr1 = 0U;
uint32_t tmp_cr2 = 0U;
uint32_t tmp_sqr1 = 0U;
/* Check ADC handle */
if(hadc == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
assert_param(IS_ADC_DATA_ALIGN(hadc->Init.DataAlign));
assert_param(IS_ADC_SCAN_MODE(hadc->Init.ScanConvMode));
assert_param(IS_FUNCTIONAL_STATE(hadc->Init.ContinuousConvMode));
assert_param(IS_ADC_EXTTRIG(hadc->Init.ExternalTrigConv));
if(hadc->Init.ScanConvMode != ADC_SCAN_DISABLE)
{
assert_param(IS_ADC_REGULAR_NB_CONV(hadc->Init.NbrOfConversion));
assert_param(IS_FUNCTIONAL_STATE(hadc->Init.DiscontinuousConvMode));
if(hadc->Init.DiscontinuousConvMode != DISABLE)
{
assert_param(IS_ADC_REGULAR_DISCONT_NUMBER(hadc->Init.NbrOfDiscConversion));
}
}
/* As prerequisite, into HAL_ADC_MspInit(), ADC clock must be configured */
/* at RCC top level. */
/* Refer to header of this file for more details on clock enabling */
/* procedure. */
/* Actions performed only if ADC is coming from state reset: */
/* - Initialization of ADC MSP */
if (hadc->State == HAL_ADC_STATE_RESET)
{
/* Initialize ADC error code */
ADC_CLEAR_ERRORCODE(hadc);
/* Allocate lock resource and initialize it */
hadc->Lock = HAL_UNLOCKED;
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
/* Init the ADC Callback settings */
hadc->ConvCpltCallback = HAL_ADC_ConvCpltCallback; /* Legacy weak callback */
hadc->ConvHalfCpltCallback = HAL_ADC_ConvHalfCpltCallback; /* Legacy weak callback */
hadc->LevelOutOfWindowCallback = HAL_ADC_LevelOutOfWindowCallback; /* Legacy weak callback */
hadc->ErrorCallback = HAL_ADC_ErrorCallback; /* Legacy weak callback */
hadc->InjectedConvCpltCallback = HAL_ADCEx_InjectedConvCpltCallback; /* Legacy weak callback */
if (hadc->MspInitCallback == NULL)
{
hadc->MspInitCallback = HAL_ADC_MspInit; /* Legacy weak MspInit */
}
/* Init the low level hardware */
hadc->MspInitCallback(hadc);
#else
/* Init the low level hardware */
HAL_ADC_MspInit(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
}
/* Stop potential conversion on going, on regular and injected groups */
/* Disable ADC peripheral */
/* Note: In case of ADC already enabled, precaution to not launch an */
/* unwanted conversion while modifying register CR2 by writing 1 to */
/* bit ADON. */
tmp_hal_status = ADC_ConversionStop_Disable(hadc);
/* Configuration of ADC parameters if previous preliminary actions are */
/* correctly completed. */
if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL) &&
(tmp_hal_status == HAL_OK) )
{
/* Set ADC state */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_REG_BUSY | HAL_ADC_STATE_INJ_BUSY,
HAL_ADC_STATE_BUSY_INTERNAL);
/* Set ADC parameters */
/* Configuration of ADC: */
/* - data alignment */
/* - external trigger to start conversion */
/* - external trigger polarity (always set to 1, because needed for all */
/* triggers: external trigger of SW start) */
/* - continuous conversion mode */
/* Note: External trigger polarity (ADC_CR2_EXTTRIG) is set into */
/* HAL_ADC_Start_xxx functions because if set in this function, */
/* a conversion on injected group would start a conversion also on */
/* regular group after ADC enabling. */
tmp_cr2 |= (hadc->Init.DataAlign |
ADC_CFGR_EXTSEL(hadc, hadc->Init.ExternalTrigConv) |
ADC_CR2_CONTINUOUS((uint32_t)hadc->Init.ContinuousConvMode) );
/* Configuration of ADC: */
/* - scan mode */
/* - discontinuous mode disable/enable */
/* - discontinuous mode number of conversions */
tmp_cr1 |= (ADC_CR1_SCAN_SET(hadc->Init.ScanConvMode));
/* Enable discontinuous mode only if continuous mode is disabled */
/* Note: If parameter "Init.ScanConvMode" is set to disable, parameter */
/* discontinuous is set anyway, but will have no effect on ADC HW. */
if (hadc->Init.DiscontinuousConvMode == ENABLE)
{
if (hadc->Init.ContinuousConvMode == DISABLE)
{
/* Enable the selected ADC regular discontinuous mode */
/* Set the number of channels to be converted in discontinuous mode */
SET_BIT(tmp_cr1, ADC_CR1_DISCEN |
ADC_CR1_DISCONTINUOUS_NUM(hadc->Init.NbrOfDiscConversion) );
}
else
{
/* ADC regular group settings continuous and sequencer discontinuous*/
/* cannot be enabled simultaneously. */
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
/* Set ADC error code to ADC IP internal error */
SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);
}
}
/* Update ADC configuration register CR1 with previous settings */
MODIFY_REG(hadc->Instance->CR1,
ADC_CR1_SCAN |
ADC_CR1_DISCEN |
ADC_CR1_DISCNUM ,
tmp_cr1 );
/* Update ADC configuration register CR2 with previous settings */
MODIFY_REG(hadc->Instance->CR2,
ADC_CR2_ALIGN |
ADC_CR2_EXTSEL |
ADC_CR2_EXTTRIG |
ADC_CR2_CONT ,
tmp_cr2 );
/* Configuration of regular group sequencer: */
/* - if scan mode is disabled, regular channels sequence length is set to */
/* 0x00: 1 channel converted (channel on regular rank 1) */
/* Parameter "NbrOfConversion" is discarded. */
/* Note: Scan mode is present by hardware on this device and, if */
/* disabled, discards automatically nb of conversions. Anyway, nb of */
/* conversions is forced to 0x00 for alignment over all STM32 devices. */
/* - if scan mode is enabled, regular channels sequence length is set to */
/* parameter "NbrOfConversion" */
if (ADC_CR1_SCAN_SET(hadc->Init.ScanConvMode) == ADC_SCAN_ENABLE)
{
tmp_sqr1 = ADC_SQR1_L_SHIFT(hadc->Init.NbrOfConversion);
}
MODIFY_REG(hadc->Instance->SQR1,
ADC_SQR1_L ,
tmp_sqr1 );
/* Check back that ADC registers have effectively been configured to */
/* ensure of no potential problem of ADC core IP clocking. */
/* Check through register CR2 (excluding bits set in other functions: */
/* execution control bits (ADON, JSWSTART, SWSTART), regular group bits */
/* (DMA), injected group bits (JEXTTRIG and JEXTSEL), channel internal */
/* measurement path bit (TSVREFE). */
if (READ_BIT(hadc->Instance->CR2, ~(ADC_CR2_ADON | ADC_CR2_DMA |
ADC_CR2_SWSTART | ADC_CR2_JSWSTART |
ADC_CR2_JEXTTRIG | ADC_CR2_JEXTSEL |
ADC_CR2_TSVREFE ))
== tmp_cr2)
{
/* Set ADC error code to none */
ADC_CLEAR_ERRORCODE(hadc);
/* Set the ADC state */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_BUSY_INTERNAL,
HAL_ADC_STATE_READY);
}
else
{
/* Update ADC state machine to error */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_BUSY_INTERNAL,
HAL_ADC_STATE_ERROR_INTERNAL);
/* Set ADC error code to ADC IP internal error */
SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);
tmp_hal_status = HAL_ERROR;
}
}
else
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);
tmp_hal_status = HAL_ERROR;
}
/* Return function status */
return tmp_hal_status;
}
/**
* @brief Deinitialize the ADC peripheral registers to their default reset
* values, with deinitialization of the ADC MSP.
* If needed, the example code can be copied and uncommented into
* function HAL_ADC_MspDeInit().
* @param hadc: ADC handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ADC_DeInit(ADC_HandleTypeDef* hadc)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
/* Check ADC handle */
if(hadc == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
/* Set ADC state */
SET_BIT(hadc->State, HAL_ADC_STATE_BUSY_INTERNAL);
/* Stop potential conversion on going, on regular and injected groups */
/* Disable ADC peripheral */
tmp_hal_status = ADC_ConversionStop_Disable(hadc);
/* Configuration of ADC parameters if previous preliminary actions are */
/* correctly completed. */
if (tmp_hal_status == HAL_OK)
{
/* ========== Reset ADC registers ========== */
/* Reset register SR */
__HAL_ADC_CLEAR_FLAG(hadc, (ADC_FLAG_AWD | ADC_FLAG_JEOC | ADC_FLAG_EOC |
ADC_FLAG_JSTRT | ADC_FLAG_STRT));
/* Reset register CR1 */
CLEAR_BIT(hadc->Instance->CR1, (ADC_CR1_AWDEN | ADC_CR1_JAWDEN | ADC_CR1_DISCNUM |
ADC_CR1_JDISCEN | ADC_CR1_DISCEN | ADC_CR1_JAUTO |
ADC_CR1_AWDSGL | ADC_CR1_SCAN | ADC_CR1_JEOCIE |
ADC_CR1_AWDIE | ADC_CR1_EOCIE | ADC_CR1_AWDCH ));
/* Reset register CR2 */
CLEAR_BIT(hadc->Instance->CR2, (ADC_CR2_TSVREFE | ADC_CR2_SWSTART | ADC_CR2_JSWSTART |
ADC_CR2_EXTTRIG | ADC_CR2_EXTSEL | ADC_CR2_JEXTTRIG |
ADC_CR2_JEXTSEL | ADC_CR2_ALIGN | ADC_CR2_DMA |
ADC_CR2_RSTCAL | ADC_CR2_CAL | ADC_CR2_CONT |
ADC_CR2_ADON ));
/* Reset register SMPR1 */
CLEAR_BIT(hadc->Instance->SMPR1, (ADC_SMPR1_SMP17 | ADC_SMPR1_SMP16 | ADC_SMPR1_SMP15 |
ADC_SMPR1_SMP14 | ADC_SMPR1_SMP13 | ADC_SMPR1_SMP12 |
ADC_SMPR1_SMP11 | ADC_SMPR1_SMP10 ));
/* Reset register SMPR2 */
CLEAR_BIT(hadc->Instance->SMPR2, (ADC_SMPR2_SMP9 | ADC_SMPR2_SMP8 | ADC_SMPR2_SMP7 |
ADC_SMPR2_SMP6 | ADC_SMPR2_SMP5 | ADC_SMPR2_SMP4 |
ADC_SMPR2_SMP3 | ADC_SMPR2_SMP2 | ADC_SMPR2_SMP1 |
ADC_SMPR2_SMP0 ));
/* Reset register JOFR1 */
CLEAR_BIT(hadc->Instance->JOFR1, ADC_JOFR1_JOFFSET1);
/* Reset register JOFR2 */
CLEAR_BIT(hadc->Instance->JOFR2, ADC_JOFR2_JOFFSET2);
/* Reset register JOFR3 */
CLEAR_BIT(hadc->Instance->JOFR3, ADC_JOFR3_JOFFSET3);
/* Reset register JOFR4 */
CLEAR_BIT(hadc->Instance->JOFR4, ADC_JOFR4_JOFFSET4);
/* Reset register HTR */
CLEAR_BIT(hadc->Instance->HTR, ADC_HTR_HT);
/* Reset register LTR */
CLEAR_BIT(hadc->Instance->LTR, ADC_LTR_LT);
/* Reset register SQR1 */
CLEAR_BIT(hadc->Instance->SQR1, ADC_SQR1_L |
ADC_SQR1_SQ16 | ADC_SQR1_SQ15 |
ADC_SQR1_SQ14 | ADC_SQR1_SQ13 );
/* Reset register SQR1 */
CLEAR_BIT(hadc->Instance->SQR1, ADC_SQR1_L |
ADC_SQR1_SQ16 | ADC_SQR1_SQ15 |
ADC_SQR1_SQ14 | ADC_SQR1_SQ13 );
/* Reset register SQR2 */
CLEAR_BIT(hadc->Instance->SQR2, ADC_SQR2_SQ12 | ADC_SQR2_SQ11 | ADC_SQR2_SQ10 |
ADC_SQR2_SQ9 | ADC_SQR2_SQ8 | ADC_SQR2_SQ7 );
/* Reset register SQR3 */
CLEAR_BIT(hadc->Instance->SQR3, ADC_SQR3_SQ6 | ADC_SQR3_SQ5 | ADC_SQR3_SQ4 |
ADC_SQR3_SQ3 | ADC_SQR3_SQ2 | ADC_SQR3_SQ1 );
/* Reset register JSQR */
CLEAR_BIT(hadc->Instance->JSQR, ADC_JSQR_JL |
ADC_JSQR_JSQ4 | ADC_JSQR_JSQ3 |
ADC_JSQR_JSQ2 | ADC_JSQR_JSQ1 );
/* Reset register JSQR */
CLEAR_BIT(hadc->Instance->JSQR, ADC_JSQR_JL |
ADC_JSQR_JSQ4 | ADC_JSQR_JSQ3 |
ADC_JSQR_JSQ2 | ADC_JSQR_JSQ1 );
/* Reset register DR */
/* bits in access mode read only, no direct reset applicable*/
/* Reset registers JDR1, JDR2, JDR3, JDR4 */
/* bits in access mode read only, no direct reset applicable*/
/* ========== Hard reset ADC peripheral ========== */
/* Performs a global reset of the entire ADC peripheral: ADC state is */
/* forced to a similar state after device power-on. */
/* If needed, copy-paste and uncomment the following reset code into */
/* function "void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)": */
/* */
/* __HAL_RCC_ADC1_FORCE_RESET() */
/* __HAL_RCC_ADC1_RELEASE_RESET() */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
if (hadc->MspDeInitCallback == NULL)
{
hadc->MspDeInitCallback = HAL_ADC_MspDeInit; /* Legacy weak MspDeInit */
}
/* DeInit the low level hardware */
hadc->MspDeInitCallback(hadc);
#else
/* DeInit the low level hardware */
HAL_ADC_MspDeInit(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
/* Set ADC error code to none */
ADC_CLEAR_ERRORCODE(hadc);
/* Set ADC state */
hadc->State = HAL_ADC_STATE_RESET;
}
/* Process unlocked */
__HAL_UNLOCK(hadc);
/* Return function status */
return tmp_hal_status;
}
/**
* @brief Initializes the ADC MSP.
* @param hadc: ADC handle
* @retval None
*/
__weak void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hadc);
/* NOTE : This function should not be modified. When the callback is needed,
function HAL_ADC_MspInit must be implemented in the user file.
*/
}
/**
* @brief DeInitializes the ADC MSP.
* @param hadc: ADC handle
* @retval None
*/
__weak void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hadc);
/* NOTE : This function should not be modified. When the callback is needed,
function HAL_ADC_MspDeInit must be implemented in the user file.
*/
}
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
/**
* @brief Register a User ADC Callback
* To be used instead of the weak predefined callback
* @param hadc Pointer to a ADC_HandleTypeDef structure that contains
* the configuration information for the specified ADC.
* @param CallbackID ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_ADC_CONVERSION_COMPLETE_CB_ID ADC conversion complete callback ID
* @arg @ref HAL_ADC_CONVERSION_HALF_CB_ID ADC conversion complete callback ID
* @arg @ref HAL_ADC_LEVEL_OUT_OF_WINDOW_1_CB_ID ADC analog watchdog 1 callback ID
* @arg @ref HAL_ADC_ERROR_CB_ID ADC error callback ID
* @arg @ref HAL_ADC_INJ_CONVERSION_COMPLETE_CB_ID ADC group injected conversion complete callback ID
* @arg @ref HAL_ADC_MSPINIT_CB_ID ADC Msp Init callback ID
* @arg @ref HAL_ADC_MSPDEINIT_CB_ID ADC Msp DeInit callback ID
* @arg @ref HAL_ADC_MSPINIT_CB_ID MspInit callback ID
* @arg @ref HAL_ADC_MSPDEINIT_CB_ID MspDeInit callback ID
* @param pCallback pointer to the Callback function
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ADC_RegisterCallback(ADC_HandleTypeDef *hadc, HAL_ADC_CallbackIDTypeDef CallbackID, pADC_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
/* Update the error code */
hadc->ErrorCode |= HAL_ADC_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
if ((hadc->State & HAL_ADC_STATE_READY) != 0)
{
switch (CallbackID)
{
case HAL_ADC_CONVERSION_COMPLETE_CB_ID :
hadc->ConvCpltCallback = pCallback;
break;
case HAL_ADC_CONVERSION_HALF_CB_ID :
hadc->ConvHalfCpltCallback = pCallback;
break;
case HAL_ADC_LEVEL_OUT_OF_WINDOW_1_CB_ID :
hadc->LevelOutOfWindowCallback = pCallback;
break;
case HAL_ADC_ERROR_CB_ID :
hadc->ErrorCallback = pCallback;
break;
case HAL_ADC_INJ_CONVERSION_COMPLETE_CB_ID :
hadc->InjectedConvCpltCallback = pCallback;
break;
case HAL_ADC_MSPINIT_CB_ID :
hadc->MspInitCallback = pCallback;
break;
case HAL_ADC_MSPDEINIT_CB_ID :
hadc->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hadc->ErrorCode |= HAL_ADC_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (HAL_ADC_STATE_RESET == hadc->State)
{
switch (CallbackID)
{
case HAL_ADC_MSPINIT_CB_ID :
hadc->MspInitCallback = pCallback;
break;
case HAL_ADC_MSPDEINIT_CB_ID :
hadc->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
hadc->ErrorCode |= HAL_ADC_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hadc->ErrorCode |= HAL_ADC_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
return status;
}
/**
* @brief Unregister a ADC Callback
* ADC callback is redirected to the weak predefined callback
* @param hadc Pointer to a ADC_HandleTypeDef structure that contains
* the configuration information for the specified ADC.
* @param CallbackID ID of the callback to be unregistered
* This parameter can be one of the following values:
* @arg @ref HAL_ADC_CONVERSION_COMPLETE_CB_ID ADC conversion complete callback ID
* @arg @ref HAL_ADC_CONVERSION_HALF_CB_ID ADC conversion complete callback ID
* @arg @ref HAL_ADC_LEVEL_OUT_OF_WINDOW_1_CB_ID ADC analog watchdog 1 callback ID
* @arg @ref HAL_ADC_ERROR_CB_ID ADC error callback ID
* @arg @ref HAL_ADC_INJ_CONVERSION_COMPLETE_CB_ID ADC group injected conversion complete callback ID
* @arg @ref HAL_ADC_MSPINIT_CB_ID ADC Msp Init callback ID
* @arg @ref HAL_ADC_MSPDEINIT_CB_ID ADC Msp DeInit callback ID
* @arg @ref HAL_ADC_MSPINIT_CB_ID MspInit callback ID
* @arg @ref HAL_ADC_MSPDEINIT_CB_ID MspDeInit callback ID
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ADC_UnRegisterCallback(ADC_HandleTypeDef *hadc, HAL_ADC_CallbackIDTypeDef CallbackID)
{
HAL_StatusTypeDef status = HAL_OK;
if ((hadc->State & HAL_ADC_STATE_READY) != 0)
{
switch (CallbackID)
{
case HAL_ADC_CONVERSION_COMPLETE_CB_ID :
hadc->ConvCpltCallback = HAL_ADC_ConvCpltCallback;
break;
case HAL_ADC_CONVERSION_HALF_CB_ID :
hadc->ConvHalfCpltCallback = HAL_ADC_ConvHalfCpltCallback;
break;
case HAL_ADC_LEVEL_OUT_OF_WINDOW_1_CB_ID :
hadc->LevelOutOfWindowCallback = HAL_ADC_LevelOutOfWindowCallback;
break;
case HAL_ADC_ERROR_CB_ID :
hadc->ErrorCallback = HAL_ADC_ErrorCallback;
break;
case HAL_ADC_INJ_CONVERSION_COMPLETE_CB_ID :
hadc->InjectedConvCpltCallback = HAL_ADCEx_InjectedConvCpltCallback;
break;
case HAL_ADC_MSPINIT_CB_ID :
hadc->MspInitCallback = HAL_ADC_MspInit; /* Legacy weak MspInit */
break;
case HAL_ADC_MSPDEINIT_CB_ID :
hadc->MspDeInitCallback = HAL_ADC_MspDeInit; /* Legacy weak MspDeInit */
break;
default :
/* Update the error code */
hadc->ErrorCode |= HAL_ADC_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (HAL_ADC_STATE_RESET == hadc->State)
{
switch (CallbackID)
{
case HAL_ADC_MSPINIT_CB_ID :
hadc->MspInitCallback = HAL_ADC_MspInit; /* Legacy weak MspInit */
break;
case HAL_ADC_MSPDEINIT_CB_ID :
hadc->MspDeInitCallback = HAL_ADC_MspDeInit; /* Legacy weak MspDeInit */
break;
default :
/* Update the error code */
hadc->ErrorCode |= HAL_ADC_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
hadc->ErrorCode |= HAL_ADC_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
return status;
}
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup ADC_Exported_Functions_Group2 IO operation functions
* @brief Input and Output operation functions
*
@verbatim
===============================================================================
##### IO operation functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Start conversion of regular group.
(+) Stop conversion of regular group.
(+) Poll for conversion complete on regular group.
(+) Poll for conversion event.
(+) Get result of regular channel conversion.
(+) Start conversion of regular group and enable interruptions.
(+) Stop conversion of regular group and disable interruptions.
(+) Handle ADC interrupt request
(+) Start conversion of regular group and enable DMA transfer.
(+) Stop conversion of regular group and disable ADC DMA transfer.
@endverbatim
* @{
*/
/**
* @brief Enables ADC, starts conversion of regular group.
* Interruptions enabled in this function: None.
* @param hadc: ADC handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
/* Process locked */
__HAL_LOCK(hadc);
/* Enable the ADC peripheral */
tmp_hal_status = ADC_Enable(hadc);
/* Start conversion if ADC is effectively enabled */
if (tmp_hal_status == HAL_OK)
{
/* Set ADC state */
/* - Clear state bitfield related to regular group conversion results */
/* - Set state bitfield related to regular operation */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_READY | HAL_ADC_STATE_REG_EOC,
HAL_ADC_STATE_REG_BUSY);
/* Set group injected state (from auto-injection) and multimode state */
/* for all cases of multimode: independent mode, multimode ADC master */
/* or multimode ADC slave (for devices with several ADCs): */
if (ADC_NONMULTIMODE_OR_MULTIMODEMASTER(hadc))
{
/* Set ADC state (ADC independent or master) */
CLEAR_BIT(hadc->State, HAL_ADC_STATE_MULTIMODE_SLAVE);
/* If conversions on group regular are also triggering group injected, */
/* update ADC state. */
if (READ_BIT(hadc->Instance->CR1, ADC_CR1_JAUTO) != RESET)
{
ADC_STATE_CLR_SET(hadc->State, HAL_ADC_STATE_INJ_EOC, HAL_ADC_STATE_INJ_BUSY);
}
}
else
{
/* Set ADC state (ADC slave) */
SET_BIT(hadc->State, HAL_ADC_STATE_MULTIMODE_SLAVE);
/* If conversions on group regular are also triggering group injected, */
/* update ADC state. */
if (ADC_MULTIMODE_AUTO_INJECTED(hadc))
{
ADC_STATE_CLR_SET(hadc->State, HAL_ADC_STATE_INJ_EOC, HAL_ADC_STATE_INJ_BUSY);
}
}
/* State machine update: Check if an injected conversion is ongoing */
if (HAL_IS_BIT_SET(hadc->State, HAL_ADC_STATE_INJ_BUSY))
{
/* Reset ADC error code fields related to conversions on group regular */
CLEAR_BIT(hadc->ErrorCode, (HAL_ADC_ERROR_OVR | HAL_ADC_ERROR_DMA));
}
else
{
/* Reset ADC all error code fields */
ADC_CLEAR_ERRORCODE(hadc);
}
/* Process unlocked */
/* Unlock before starting ADC conversions: in case of potential */
/* interruption, to let the process to ADC IRQ Handler. */
__HAL_UNLOCK(hadc);
/* Clear regular group conversion flag */
/* (To ensure of no unknown state from potential previous ADC operations) */
__HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_EOC);
/* Enable conversion of regular group. */
/* If software start has been selected, conversion starts immediately. */
/* If external trigger has been selected, conversion will start at next */
/* trigger event. */
/* Case of multimode enabled: */
/* - if ADC is slave, ADC is enabled only (conversion is not started). */
/* - if ADC is master, ADC is enabled and conversion is started. */
/* If ADC is master, ADC is enabled and conversion is started. */
/* Note: Alternate trigger for single conversion could be to force an */
/* additional set of bit ADON "hadc->Instance->CR2 |= ADC_CR2_ADON;"*/
if (ADC_IS_SOFTWARE_START_REGULAR(hadc) &&
ADC_NONMULTIMODE_OR_MULTIMODEMASTER(hadc) )
{
/* Start ADC conversion on regular group with SW start */
SET_BIT(hadc->Instance->CR2, (ADC_CR2_SWSTART | ADC_CR2_EXTTRIG));
}
else
{
/* Start ADC conversion on regular group with external trigger */
SET_BIT(hadc->Instance->CR2, ADC_CR2_EXTTRIG);
}
}
else
{
/* Process unlocked */
__HAL_UNLOCK(hadc);
}
/* Return function status */
return tmp_hal_status;
}
/**
* @brief Stop ADC conversion of regular group (and injected channels in
* case of auto_injection mode), disable ADC peripheral.
* @note: ADC peripheral disable is forcing stop of potential
* conversion on injected group. If injected group is under use, it
* should be preliminarily stopped using HAL_ADCEx_InjectedStop function.
* @param hadc: ADC handle
* @retval HAL status.
*/
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef* hadc)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
/* Process locked */
__HAL_LOCK(hadc);
/* Stop potential conversion on going, on regular and injected groups */
/* Disable ADC peripheral */
tmp_hal_status = ADC_ConversionStop_Disable(hadc);
/* Check if ADC is effectively disabled */
if (tmp_hal_status == HAL_OK)
{
/* Set ADC state */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_REG_BUSY | HAL_ADC_STATE_INJ_BUSY,
HAL_ADC_STATE_READY);
}
/* Process unlocked */
__HAL_UNLOCK(hadc);
/* Return function status */
return tmp_hal_status;
}
/**
* @brief Wait for regular group conversion to be completed.
* @note This function cannot be used in a particular setup: ADC configured
* in DMA mode.
* In this case, DMA resets the flag EOC and polling cannot be
* performed on each conversion.
* @note On STM32F1 devices, limitation in case of sequencer enabled
* (several ranks selected): polling cannot be done on each
* conversion inside the sequence. In this case, polling is replaced by
* wait for maximum conversion time.
* @param hadc: ADC handle
* @param Timeout: Timeout value in millisecond.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout)
{
uint32_t tickstart = 0U;
/* Variables for polling in case of scan mode enabled and polling for each */
/* conversion. */
__IO uint32_t Conversion_Timeout_CPU_cycles = 0U;
uint32_t Conversion_Timeout_CPU_cycles_max = 0U;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
/* Get tick count */
tickstart = HAL_GetTick();
/* Verification that ADC configuration is compliant with polling for */
/* each conversion: */
/* Particular case is ADC configured in DMA mode */
if (HAL_IS_BIT_SET(hadc->Instance->CR2, ADC_CR2_DMA))
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
/* Process unlocked */
__HAL_UNLOCK(hadc);
return HAL_ERROR;
}
/* Polling for end of conversion: differentiation if single/sequence */
/* conversion. */
/* - If single conversion for regular group (Scan mode disabled or enabled */
/* with NbrOfConversion =1), flag EOC is used to determine the */
/* conversion completion. */
/* - If sequence conversion for regular group (scan mode enabled and */
/* NbrOfConversion >=2), flag EOC is set only at the end of the */
/* sequence. */
/* To poll for each conversion, the maximum conversion time is computed */
/* from ADC conversion time (selected sampling time + conversion time of */
/* 12.5 ADC clock cycles) and APB2/ADC clock prescalers (depending on */
/* settings, conversion time range can be from 28 to 32256 CPU cycles). */
/* As flag EOC is not set after each conversion, no timeout status can */
/* be set. */
if (HAL_IS_BIT_CLR(hadc->Instance->CR1, ADC_CR1_SCAN) &&
HAL_IS_BIT_CLR(hadc->Instance->SQR1, ADC_SQR1_L) )
{
/* Wait until End of Conversion flag is raised */
while(HAL_IS_BIT_CLR(hadc->Instance->SR, ADC_FLAG_EOC))
{
/* Check if timeout is disabled (set to infinite wait) */
if(Timeout != HAL_MAX_DELAY)
{
if((Timeout == 0U) || ((HAL_GetTick() - tickstart ) > Timeout))
{
/* New check to avoid false timeout detection in case of preemption */
if(HAL_IS_BIT_CLR(hadc->Instance->SR, ADC_FLAG_EOC))
{
/* Update ADC state machine to timeout */
SET_BIT(hadc->State, HAL_ADC_STATE_TIMEOUT);
/* Process unlocked */
__HAL_UNLOCK(hadc);
return HAL_TIMEOUT;
}
}
}
}
}
else
{
/* Replace polling by wait for maximum conversion time */
/* - Computation of CPU clock cycles corresponding to ADC clock cycles */
/* and ADC maximum conversion cycles on all channels. */
/* - Wait for the expected ADC clock cycles delay */
Conversion_Timeout_CPU_cycles_max = ((SystemCoreClock
/ HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_ADC))
* ADC_CONVCYCLES_MAX_RANGE(hadc) );
while(Conversion_Timeout_CPU_cycles < Conversion_Timeout_CPU_cycles_max)
{
/* Check if timeout is disabled (set to infinite wait) */
if(Timeout != HAL_MAX_DELAY)
{
if((Timeout == 0U) || ((HAL_GetTick() - tickstart) > Timeout))
{
/* New check to avoid false timeout detection in case of preemption */
if(Conversion_Timeout_CPU_cycles < Conversion_Timeout_CPU_cycles_max)
{
/* Update ADC state machine to timeout */
SET_BIT(hadc->State, HAL_ADC_STATE_TIMEOUT);
/* Process unlocked */
__HAL_UNLOCK(hadc);
return HAL_TIMEOUT;
}
}
}
Conversion_Timeout_CPU_cycles ++;
}
}
/* Clear regular group conversion flag */
__HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_STRT | ADC_FLAG_EOC);
/* Update ADC state machine */
SET_BIT(hadc->State, HAL_ADC_STATE_REG_EOC);
/* Determine whether any further conversion upcoming on group regular */
/* by external trigger, continuous mode or scan sequence on going. */
/* Note: On STM32F1 devices, in case of sequencer enabled */
/* (several ranks selected), end of conversion flag is raised */
/* at the end of the sequence. */
if(ADC_IS_SOFTWARE_START_REGULAR(hadc) &&
(hadc->Init.ContinuousConvMode == DISABLE) )
{
/* Set ADC state */
CLEAR_BIT(hadc->State, HAL_ADC_STATE_REG_BUSY);
if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_INJ_BUSY))
{
SET_BIT(hadc->State, HAL_ADC_STATE_READY);
}
}
/* Return ADC state */
return HAL_OK;
}
/**
* @brief Poll for conversion event.
* @param hadc: ADC handle
* @param EventType: the ADC event type.
* This parameter can be one of the following values:
* @arg ADC_AWD_EVENT: ADC Analog watchdog event.
* @param Timeout: Timeout value in millisecond.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ADC_PollForEvent(ADC_HandleTypeDef* hadc, uint32_t EventType, uint32_t Timeout)
{
uint32_t tickstart = 0U;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
assert_param(IS_ADC_EVENT_TYPE(EventType));
/* Get tick count */
tickstart = HAL_GetTick();
/* Check selected event flag */
while(__HAL_ADC_GET_FLAG(hadc, EventType) == RESET)
{
/* Check if timeout is disabled (set to infinite wait) */
if(Timeout != HAL_MAX_DELAY)
{
if((Timeout == 0U) || ((HAL_GetTick() - tickstart ) > Timeout))
{
/* New check to avoid false timeout detection in case of preemption */
if(__HAL_ADC_GET_FLAG(hadc, EventType) == RESET)
{
/* Update ADC state machine to timeout */
SET_BIT(hadc->State, HAL_ADC_STATE_TIMEOUT);
/* Process unlocked */
__HAL_UNLOCK(hadc);
return HAL_TIMEOUT;
}
}
}
}
/* Analog watchdog (level out of window) event */
/* Set ADC state */
SET_BIT(hadc->State, HAL_ADC_STATE_AWD1);
/* Clear ADC analog watchdog flag */
__HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_AWD);
/* Return ADC state */
return HAL_OK;
}
/**
* @brief Enables ADC, starts conversion of regular group with interruption.
* Interruptions enabled in this function:
* - EOC (end of conversion of regular group)
* Each of these interruptions has its dedicated callback function.
* @param hadc: ADC handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
/* Process locked */
__HAL_LOCK(hadc);
/* Enable the ADC peripheral */
tmp_hal_status = ADC_Enable(hadc);
/* Start conversion if ADC is effectively enabled */
if (tmp_hal_status == HAL_OK)
{
/* Set ADC state */
/* - Clear state bitfield related to regular group conversion results */
/* - Set state bitfield related to regular operation */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_READY | HAL_ADC_STATE_REG_EOC | HAL_ADC_STATE_REG_OVR | HAL_ADC_STATE_REG_EOSMP,
HAL_ADC_STATE_REG_BUSY);
/* Set group injected state (from auto-injection) and multimode state */
/* for all cases of multimode: independent mode, multimode ADC master */
/* or multimode ADC slave (for devices with several ADCs): */
if (ADC_NONMULTIMODE_OR_MULTIMODEMASTER(hadc))
{
/* Set ADC state (ADC independent or master) */
CLEAR_BIT(hadc->State, HAL_ADC_STATE_MULTIMODE_SLAVE);
/* If conversions on group regular are also triggering group injected, */
/* update ADC state. */
if (READ_BIT(hadc->Instance->CR1, ADC_CR1_JAUTO) != RESET)
{
ADC_STATE_CLR_SET(hadc->State, HAL_ADC_STATE_INJ_EOC, HAL_ADC_STATE_INJ_BUSY);
}
}
else
{
/* Set ADC state (ADC slave) */
SET_BIT(hadc->State, HAL_ADC_STATE_MULTIMODE_SLAVE);
/* If conversions on group regular are also triggering group injected, */
/* update ADC state. */
if (ADC_MULTIMODE_AUTO_INJECTED(hadc))
{
ADC_STATE_CLR_SET(hadc->State, HAL_ADC_STATE_INJ_EOC, HAL_ADC_STATE_INJ_BUSY);
}
}
/* State machine update: Check if an injected conversion is ongoing */
if (HAL_IS_BIT_SET(hadc->State, HAL_ADC_STATE_INJ_BUSY))
{
/* Reset ADC error code fields related to conversions on group regular */
CLEAR_BIT(hadc->ErrorCode, (HAL_ADC_ERROR_OVR | HAL_ADC_ERROR_DMA));
}
else
{
/* Reset ADC all error code fields */
ADC_CLEAR_ERRORCODE(hadc);
}
/* Process unlocked */
/* Unlock before starting ADC conversions: in case of potential */
/* interruption, to let the process to ADC IRQ Handler. */
__HAL_UNLOCK(hadc);
/* Clear regular group conversion flag and overrun flag */
/* (To ensure of no unknown state from potential previous ADC operations) */
__HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_EOC);
/* Enable end of conversion interrupt for regular group */
__HAL_ADC_ENABLE_IT(hadc, ADC_IT_EOC);
/* Enable conversion of regular group. */
/* If software start has been selected, conversion starts immediately. */
/* If external trigger has been selected, conversion will start at next */
/* trigger event. */
/* Case of multimode enabled: */
/* - if ADC is slave, ADC is enabled only (conversion is not started). */
/* - if ADC is master, ADC is enabled and conversion is started. */
if (ADC_IS_SOFTWARE_START_REGULAR(hadc) &&
ADC_NONMULTIMODE_OR_MULTIMODEMASTER(hadc) )
{
/* Start ADC conversion on regular group with SW start */
SET_BIT(hadc->Instance->CR2, (ADC_CR2_SWSTART | ADC_CR2_EXTTRIG));
}
else
{
/* Start ADC conversion on regular group with external trigger */
SET_BIT(hadc->Instance->CR2, ADC_CR2_EXTTRIG);
}
}
else
{
/* Process unlocked */
__HAL_UNLOCK(hadc);
}
/* Return function status */
return tmp_hal_status;
}
/**
* @brief Stop ADC conversion of regular group (and injected group in
* case of auto_injection mode), disable interrution of
* end-of-conversion, disable ADC peripheral.
* @param hadc: ADC handle
* @retval None
*/
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef* hadc)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
/* Process locked */
__HAL_LOCK(hadc);
/* Stop potential conversion on going, on regular and injected groups */
/* Disable ADC peripheral */
tmp_hal_status = ADC_ConversionStop_Disable(hadc);
/* Check if ADC is effectively disabled */
if (tmp_hal_status == HAL_OK)
{
/* Disable ADC end of conversion interrupt for regular group */
__HAL_ADC_DISABLE_IT(hadc, ADC_IT_EOC);
/* Set ADC state */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_REG_BUSY | HAL_ADC_STATE_INJ_BUSY,
HAL_ADC_STATE_READY);
}
/* Process unlocked */
__HAL_UNLOCK(hadc);
/* Return function status */
return tmp_hal_status;
}
/**
* @brief Enables ADC, starts conversion of regular group and transfers result
* through DMA.
* Interruptions enabled in this function:
* - DMA transfer complete
* - DMA half transfer
* Each of these interruptions has its dedicated callback function.
* @note For devices with several ADCs: This function is for single-ADC mode
* only. For multimode, use the dedicated MultimodeStart function.
* @note On STM32F1 devices, only ADC1 and ADC3 (ADC availability depending
* on devices) have DMA capability.
* ADC2 converted data can be transferred in dual ADC mode using DMA
* of ADC1 (ADC master in multimode).
* In case of using ADC1 with DMA on a device featuring 2 ADC
* instances: ADC1 conversion register DR contains ADC1 conversion
* result (ADC1 register DR bits 0 to 11) and, additionally, ADC2 last
* conversion result (ADC1 register DR bits 16 to 27). Therefore, to
* have DMA transferring the conversion results of ADC1 only, DMA must
* be configured to transfer size: half word.
* @param hadc: ADC handle
* @param pData: The destination Buffer address.
* @param Length: The length of data to be transferred from ADC peripheral to memory.
* @retval None
*/
HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
/* Check the parameters */
assert_param(IS_ADC_DMA_CAPABILITY_INSTANCE(hadc->Instance));
/* Verification if multimode is disabled (for devices with several ADC) */
/* If multimode is enabled, dedicated function multimode conversion */
/* start DMA must be used. */
if(ADC_MULTIMODE_IS_ENABLE(hadc) == RESET)
{
/* Process locked */
__HAL_LOCK(hadc);
/* Enable the ADC peripheral */
tmp_hal_status = ADC_Enable(hadc);
/* Start conversion if ADC is effectively enabled */
if (tmp_hal_status == HAL_OK)
{
/* Set ADC state */
/* - Clear state bitfield related to regular group conversion results */
/* - Set state bitfield related to regular operation */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_READY | HAL_ADC_STATE_REG_EOC | HAL_ADC_STATE_REG_OVR | HAL_ADC_STATE_REG_EOSMP,
HAL_ADC_STATE_REG_BUSY);
/* Set group injected state (from auto-injection) and multimode state */
/* for all cases of multimode: independent mode, multimode ADC master */
/* or multimode ADC slave (for devices with several ADCs): */
if (ADC_NONMULTIMODE_OR_MULTIMODEMASTER(hadc))
{
/* Set ADC state (ADC independent or master) */
CLEAR_BIT(hadc->State, HAL_ADC_STATE_MULTIMODE_SLAVE);
/* If conversions on group regular are also triggering group injected, */
/* update ADC state. */
if (READ_BIT(hadc->Instance->CR1, ADC_CR1_JAUTO) != RESET)
{
ADC_STATE_CLR_SET(hadc->State, HAL_ADC_STATE_INJ_EOC, HAL_ADC_STATE_INJ_BUSY);
}
}
else
{
/* Set ADC state (ADC slave) */
SET_BIT(hadc->State, HAL_ADC_STATE_MULTIMODE_SLAVE);
/* If conversions on group regular are also triggering group injected, */
/* update ADC state. */
if (ADC_MULTIMODE_AUTO_INJECTED(hadc))
{
ADC_STATE_CLR_SET(hadc->State, HAL_ADC_STATE_INJ_EOC, HAL_ADC_STATE_INJ_BUSY);
}
}
/* State machine update: Check if an injected conversion is ongoing */
if (HAL_IS_BIT_SET(hadc->State, HAL_ADC_STATE_INJ_BUSY))
{
/* Reset ADC error code fields related to conversions on group regular */
CLEAR_BIT(hadc->ErrorCode, (HAL_ADC_ERROR_OVR | HAL_ADC_ERROR_DMA));
}
else
{
/* Reset ADC all error code fields */
ADC_CLEAR_ERRORCODE(hadc);
}
/* Process unlocked */
/* Unlock before starting ADC conversions: in case of potential */
/* interruption, to let the process to ADC IRQ Handler. */
__HAL_UNLOCK(hadc);
/* Set the DMA transfer complete callback */
hadc->DMA_Handle->XferCpltCallback = ADC_DMAConvCplt;
/* Set the DMA half transfer complete callback */
hadc->DMA_Handle->XferHalfCpltCallback = ADC_DMAHalfConvCplt;
/* Set the DMA error callback */
hadc->DMA_Handle->XferErrorCallback = ADC_DMAError;
/* Manage ADC and DMA start: ADC overrun interruption, DMA start, ADC */
/* start (in case of SW start): */
/* Clear regular group conversion flag and overrun flag */
/* (To ensure of no unknown state from potential previous ADC */
/* operations) */
__HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_EOC);
/* Enable ADC DMA mode */
SET_BIT(hadc->Instance->CR2, ADC_CR2_DMA);
/* Start the DMA channel */
HAL_DMA_Start_IT(hadc->DMA_Handle, (uint32_t)&hadc->Instance->DR, (uint32_t)pData, Length);
/* Enable conversion of regular group. */
/* If software start has been selected, conversion starts immediately. */
/* If external trigger has been selected, conversion will start at next */
/* trigger event. */
if (ADC_IS_SOFTWARE_START_REGULAR(hadc))
{
/* Start ADC conversion on regular group with SW start */
SET_BIT(hadc->Instance->CR2, (ADC_CR2_SWSTART | ADC_CR2_EXTTRIG));
}
else
{
/* Start ADC conversion on regular group with external trigger */
SET_BIT(hadc->Instance->CR2, ADC_CR2_EXTTRIG);
}
}
else
{
/* Process unlocked */
__HAL_UNLOCK(hadc);
}
}
else
{
tmp_hal_status = HAL_ERROR;
}
/* Return function status */
return tmp_hal_status;
}
/**
* @brief Stop ADC conversion of regular group (and injected group in
* case of auto_injection mode), disable ADC DMA transfer, disable
* ADC peripheral.
* @note: ADC peripheral disable is forcing stop of potential
* conversion on injected group. If injected group is under use, it
* should be preliminarily stopped using HAL_ADCEx_InjectedStop function.
* @note For devices with several ADCs: This function is for single-ADC mode
* only. For multimode, use the dedicated MultimodeStop function.
* @note On STM32F1 devices, only ADC1 and ADC3 (ADC availability depending
* on devices) have DMA capability.
* @param hadc: ADC handle
* @retval HAL status.
*/
HAL_StatusTypeDef HAL_ADC_Stop_DMA(ADC_HandleTypeDef* hadc)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
/* Check the parameters */
assert_param(IS_ADC_DMA_CAPABILITY_INSTANCE(hadc->Instance));
/* Process locked */
__HAL_LOCK(hadc);
/* Stop potential conversion on going, on regular and injected groups */
/* Disable ADC peripheral */
tmp_hal_status = ADC_ConversionStop_Disable(hadc);
/* Check if ADC is effectively disabled */
if (tmp_hal_status == HAL_OK)
{
/* Disable ADC DMA mode */
CLEAR_BIT(hadc->Instance->CR2, ADC_CR2_DMA);
/* Disable the DMA channel (in case of DMA in circular mode or stop while */
/* DMA transfer is on going) */
if (hadc->DMA_Handle->State == HAL_DMA_STATE_BUSY)
{
tmp_hal_status = HAL_DMA_Abort(hadc->DMA_Handle);
/* Check if DMA channel effectively disabled */
if (tmp_hal_status == HAL_OK)
{
/* Set ADC state */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_REG_BUSY | HAL_ADC_STATE_INJ_BUSY,
HAL_ADC_STATE_READY);
}
else
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_DMA);
}
}
}
/* Process unlocked */
__HAL_UNLOCK(hadc);
/* Return function status */
return tmp_hal_status;
}
/**
* @brief Get ADC regular group conversion result.
* @note Reading register DR automatically clears ADC flag EOC
* (ADC group regular end of unitary conversion).
* @note This function does not clear ADC flag EOS
* (ADC group regular end of sequence conversion).
* Occurrence of flag EOS rising:
* - If sequencer is composed of 1 rank, flag EOS is equivalent
* to flag EOC.
* - If sequencer is composed of several ranks, during the scan
* sequence flag EOC only is raised, at the end of the scan sequence
* both flags EOC and EOS are raised.
* To clear this flag, either use function:
* in programming model IT: @ref HAL_ADC_IRQHandler(), in programming
* model polling: @ref HAL_ADC_PollForConversion()
* or @ref __HAL_ADC_CLEAR_FLAG(&hadc, ADC_FLAG_EOS).
* @param hadc: ADC handle
* @retval ADC group regular conversion data
*/
uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc)
{
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
/* Note: EOC flag is not cleared here by software because automatically */
/* cleared by hardware when reading register DR. */
/* Return ADC converted value */
return hadc->Instance->DR;
}
/**
* @brief Handles ADC interrupt request
* @param hadc: ADC handle
* @retval None
*/
void HAL_ADC_IRQHandler(ADC_HandleTypeDef* hadc)
{
uint32_t tmp_sr = hadc->Instance->SR;
uint32_t tmp_cr1 = hadc->Instance->CR1;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
assert_param(IS_FUNCTIONAL_STATE(hadc->Init.ContinuousConvMode));
assert_param(IS_ADC_REGULAR_NB_CONV(hadc->Init.NbrOfConversion));
/* ========== Check End of Conversion flag for regular group ========== */
if((tmp_cr1 & ADC_IT_EOC) == ADC_IT_EOC)
{
if((tmp_sr & ADC_FLAG_EOC) == ADC_FLAG_EOC)
{
/* Update state machine on conversion status if not in error state */
if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL))
{
/* Set ADC state */
SET_BIT(hadc->State, HAL_ADC_STATE_REG_EOC);
}
/* Determine whether any further conversion upcoming on group regular */
/* by external trigger, continuous mode or scan sequence on going. */
/* Note: On STM32F1 devices, in case of sequencer enabled */
/* (several ranks selected), end of conversion flag is raised */
/* at the end of the sequence. */
if(ADC_IS_SOFTWARE_START_REGULAR(hadc) &&
(hadc->Init.ContinuousConvMode == DISABLE) )
{
/* Disable ADC end of conversion interrupt on group regular */
__HAL_ADC_DISABLE_IT(hadc, ADC_IT_EOC);
/* Set ADC state */
CLEAR_BIT(hadc->State, HAL_ADC_STATE_REG_BUSY);
if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_INJ_BUSY))
{
SET_BIT(hadc->State, HAL_ADC_STATE_READY);
}
}
/* Conversion complete callback */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
hadc->ConvCpltCallback(hadc);
#else
HAL_ADC_ConvCpltCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
/* Clear regular group conversion flag */
__HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_STRT | ADC_FLAG_EOC);
}
}
/* ========== Check End of Conversion flag for injected group ========== */
if((tmp_cr1 & ADC_IT_JEOC) == ADC_IT_JEOC)
{
if((tmp_sr & ADC_FLAG_JEOC) == ADC_FLAG_JEOC)
{
/* Update state machine on conversion status if not in error state */
if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL))
{
/* Set ADC state */
SET_BIT(hadc->State, HAL_ADC_STATE_INJ_EOC);
}
/* Determine whether any further conversion upcoming on group injected */
/* by external trigger, scan sequence on going or by automatic injected */
/* conversion from group regular (same conditions as group regular */
/* interruption disabling above). */
/* Note: On STM32F1 devices, in case of sequencer enabled */
/* (several ranks selected), end of conversion flag is raised */
/* at the end of the sequence. */
if(ADC_IS_SOFTWARE_START_INJECTED(hadc) ||
(HAL_IS_BIT_CLR(hadc->Instance->CR1, ADC_CR1_JAUTO) &&
(ADC_IS_SOFTWARE_START_REGULAR(hadc) &&
(hadc->Init.ContinuousConvMode == DISABLE) ) ) )
{
/* Disable ADC end of conversion interrupt on group injected */
__HAL_ADC_DISABLE_IT(hadc, ADC_IT_JEOC);
/* Set ADC state */
CLEAR_BIT(hadc->State, HAL_ADC_STATE_INJ_BUSY);
if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_REG_BUSY))
{
SET_BIT(hadc->State, HAL_ADC_STATE_READY);
}
}
/* Conversion complete callback */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
hadc->InjectedConvCpltCallback(hadc);
#else
HAL_ADCEx_InjectedConvCpltCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
/* Clear injected group conversion flag */
__HAL_ADC_CLEAR_FLAG(hadc, (ADC_FLAG_JSTRT | ADC_FLAG_JEOC));
}
}
/* ========== Check Analog watchdog flags ========== */
if((tmp_cr1 & ADC_IT_AWD) == ADC_IT_AWD)
{
if((tmp_sr & ADC_FLAG_AWD) == ADC_FLAG_AWD)
{
/* Set ADC state */
SET_BIT(hadc->State, HAL_ADC_STATE_AWD1);
/* Level out of window callback */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
hadc->LevelOutOfWindowCallback(hadc);
#else
HAL_ADC_LevelOutOfWindowCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
/* Clear the ADC analog watchdog flag */
__HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_AWD);
}
}
}
/**
* @brief Conversion complete callback in non blocking mode
* @param hadc: ADC handle
* @retval None
*/
__weak void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hadc);
/* NOTE : This function should not be modified. When the callback is needed,
function HAL_ADC_ConvCpltCallback must be implemented in the user file.
*/
}
/**
* @brief Conversion DMA half-transfer callback in non blocking mode
* @param hadc: ADC handle
* @retval None
*/
__weak void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hadc);
/* NOTE : This function should not be modified. When the callback is needed,
function HAL_ADC_ConvHalfCpltCallback must be implemented in the user file.
*/
}
/**
* @brief Analog watchdog callback in non blocking mode.
* @param hadc: ADC handle
* @retval None
*/
__weak void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef* hadc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hadc);
/* NOTE : This function should not be modified. When the callback is needed,
function HAL_ADC_LevelOutOfWindowCallback must be implemented in the user file.
*/
}
/**
* @brief ADC error callback in non blocking mode
* (ADC conversion with interruption or transfer by DMA)
* @param hadc: ADC handle
* @retval None
*/
__weak void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hadc);
/* NOTE : This function should not be modified. When the callback is needed,
function HAL_ADC_ErrorCallback must be implemented in the user file.
*/
}
/**
* @}
*/
/** @defgroup ADC_Exported_Functions_Group3 Peripheral Control functions
* @brief Peripheral Control functions
*
@verbatim
===============================================================================
##### Peripheral Control functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Configure channels on regular group
(+) Configure the analog watchdog
@endverbatim
* @{
*/
/**
* @brief Configures the the selected channel to be linked to the regular
* group.
* @note In case of usage of internal measurement channels:
* Vbat/VrefInt/TempSensor.
* These internal paths can be be disabled using function
* HAL_ADC_DeInit().
* @note Possibility to update parameters on the fly:
* This function initializes channel into regular group, following
* calls to this function can be used to reconfigure some parameters
* of structure "ADC_ChannelConfTypeDef" on the fly, without resetting
* the ADC.
* The setting of these parameters is conditioned to ADC state.
* For parameters constraints, see comments of structure
* "ADC_ChannelConfTypeDef".
* @param hadc: ADC handle
* @param sConfig: Structure of ADC channel for regular group.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ADC_ConfigChannel(ADC_HandleTypeDef* hadc, ADC_ChannelConfTypeDef* sConfig)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
__IO uint32_t wait_loop_index = 0U;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
assert_param(IS_ADC_CHANNEL(sConfig->Channel));
assert_param(IS_ADC_REGULAR_RANK(sConfig->Rank));
assert_param(IS_ADC_SAMPLE_TIME(sConfig->SamplingTime));
/* Process locked */
__HAL_LOCK(hadc);
/* Regular sequence configuration */
/* For Rank 1 to 6 */
if (sConfig->Rank < 7U)
{
MODIFY_REG(hadc->Instance->SQR3 ,
ADC_SQR3_RK(ADC_SQR3_SQ1, sConfig->Rank) ,
ADC_SQR3_RK(sConfig->Channel, sConfig->Rank) );
}
/* For Rank 7 to 12 */
else if (sConfig->Rank < 13U)
{
MODIFY_REG(hadc->Instance->SQR2 ,
ADC_SQR2_RK(ADC_SQR2_SQ7, sConfig->Rank) ,
ADC_SQR2_RK(sConfig->Channel, sConfig->Rank) );
}
/* For Rank 13 to 16 */
else
{
MODIFY_REG(hadc->Instance->SQR1 ,
ADC_SQR1_RK(ADC_SQR1_SQ13, sConfig->Rank) ,
ADC_SQR1_RK(sConfig->Channel, sConfig->Rank) );
}
/* Channel sampling time configuration */
/* For channels 10 to 17 */
if (sConfig->Channel >= ADC_CHANNEL_10)
{
MODIFY_REG(hadc->Instance->SMPR1 ,
ADC_SMPR1(ADC_SMPR1_SMP10, sConfig->Channel) ,
ADC_SMPR1(sConfig->SamplingTime, sConfig->Channel) );
}
else /* For channels 0 to 9 */
{
MODIFY_REG(hadc->Instance->SMPR2 ,
ADC_SMPR2(ADC_SMPR2_SMP0, sConfig->Channel) ,
ADC_SMPR2(sConfig->SamplingTime, sConfig->Channel) );
}
/* If ADC1 Channel_16 or Channel_17 is selected, enable Temperature sensor */
/* and VREFINT measurement path. */
if ((sConfig->Channel == ADC_CHANNEL_TEMPSENSOR) ||
(sConfig->Channel == ADC_CHANNEL_VREFINT) )
{
/* For STM32F1 devices with several ADC: Only ADC1 can access internal */
/* measurement channels (VrefInt/TempSensor). If these channels are */
/* intended to be set on other ADC instances, an error is reported. */
if (hadc->Instance == ADC1)
{
if (READ_BIT(hadc->Instance->CR2, ADC_CR2_TSVREFE) == RESET)
{
SET_BIT(hadc->Instance->CR2, ADC_CR2_TSVREFE);
if (sConfig->Channel == ADC_CHANNEL_TEMPSENSOR)
{
/* Delay for temperature sensor stabilization time */
/* Compute number of CPU cycles to wait for */
wait_loop_index = (ADC_TEMPSENSOR_DELAY_US * (SystemCoreClock / 1000000U));
while(wait_loop_index != 0U)
{
wait_loop_index--;
}
}
}
}
else
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
tmp_hal_status = HAL_ERROR;
}
}
/* Process unlocked */
__HAL_UNLOCK(hadc);
/* Return function status */
return tmp_hal_status;
}
/**
* @brief Configures the analog watchdog.
* @note Analog watchdog thresholds can be modified while ADC conversion
* is on going.
* In this case, some constraints must be taken into account:
* the programmed threshold values are effective from the next
* ADC EOC (end of unitary conversion).
* Considering that registers write delay may happen due to
* bus activity, this might cause an uncertainty on the
* effective timing of the new programmed threshold values.
* @param hadc: ADC handle
* @param AnalogWDGConfig: Structure of ADC analog watchdog configuration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ADC_AnalogWDGConfig(ADC_HandleTypeDef* hadc, ADC_AnalogWDGConfTypeDef* AnalogWDGConfig)
{
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
assert_param(IS_ADC_ANALOG_WATCHDOG_MODE(AnalogWDGConfig->WatchdogMode));
assert_param(IS_FUNCTIONAL_STATE(AnalogWDGConfig->ITMode));
assert_param(IS_ADC_RANGE(AnalogWDGConfig->HighThreshold));
assert_param(IS_ADC_RANGE(AnalogWDGConfig->LowThreshold));
if((AnalogWDGConfig->WatchdogMode == ADC_ANALOGWATCHDOG_SINGLE_REG) ||
(AnalogWDGConfig->WatchdogMode == ADC_ANALOGWATCHDOG_SINGLE_INJEC) ||
(AnalogWDGConfig->WatchdogMode == ADC_ANALOGWATCHDOG_SINGLE_REGINJEC) )
{
assert_param(IS_ADC_CHANNEL(AnalogWDGConfig->Channel));
}
/* Process locked */
__HAL_LOCK(hadc);
/* Analog watchdog configuration */
/* Configure ADC Analog watchdog interrupt */
if(AnalogWDGConfig->ITMode == ENABLE)
{
/* Enable the ADC Analog watchdog interrupt */
__HAL_ADC_ENABLE_IT(hadc, ADC_IT_AWD);
}
else
{
/* Disable the ADC Analog watchdog interrupt */
__HAL_ADC_DISABLE_IT(hadc, ADC_IT_AWD);
}
/* Configuration of analog watchdog: */
/* - Set the analog watchdog enable mode: regular and/or injected groups, */
/* one or all channels. */
/* - Set the Analog watchdog channel (is not used if watchdog */
/* mode "all channels": ADC_CFGR_AWD1SGL=0). */
MODIFY_REG(hadc->Instance->CR1 ,
ADC_CR1_AWDSGL |
ADC_CR1_JAWDEN |
ADC_CR1_AWDEN |
ADC_CR1_AWDCH ,
AnalogWDGConfig->WatchdogMode |
AnalogWDGConfig->Channel );
/* Set the high threshold */
WRITE_REG(hadc->Instance->HTR, AnalogWDGConfig->HighThreshold);
/* Set the low threshold */
WRITE_REG(hadc->Instance->LTR, AnalogWDGConfig->LowThreshold);
/* Process unlocked */
__HAL_UNLOCK(hadc);
/* Return function status */
return HAL_OK;
}
/**
* @}
*/
/** @defgroup ADC_Exported_Functions_Group4 Peripheral State functions
* @brief Peripheral State functions
*
@verbatim
===============================================================================
##### Peripheral State and Errors functions #####
===============================================================================
[..]
This subsection provides functions to get in run-time the status of the
peripheral.
(+) Check the ADC state
(+) Check the ADC error code
@endverbatim
* @{
*/
/**
* @brief return the ADC state
* @param hadc: ADC handle
* @retval HAL state
*/
uint32_t HAL_ADC_GetState(ADC_HandleTypeDef* hadc)
{
/* Return ADC state */
return hadc->State;
}
/**
* @brief Return the ADC error code
* @param hadc: ADC handle
* @retval ADC Error Code
*/
uint32_t HAL_ADC_GetError(ADC_HandleTypeDef *hadc)
{
return hadc->ErrorCode;
}
/**
* @}
*/
/**
* @}
*/
/** @defgroup ADC_Private_Functions ADC Private Functions
* @{
*/
/**
* @brief Enable the selected ADC.
* @note Prerequisite condition to use this function: ADC must be disabled
* and voltage regulator must be enabled (done into HAL_ADC_Init()).
* @param hadc: ADC handle
* @retval HAL status.
*/
HAL_StatusTypeDef ADC_Enable(ADC_HandleTypeDef* hadc)
{
uint32_t tickstart = 0U;
__IO uint32_t wait_loop_index = 0U;
/* ADC enable and wait for ADC ready (in case of ADC is disabled or */
/* enabling phase not yet completed: flag ADC ready not yet set). */
/* Timeout implemented to not be stuck if ADC cannot be enabled (possible */
/* causes: ADC clock not running, ...). */
if (ADC_IS_ENABLE(hadc) == RESET)
{
/* Enable the Peripheral */
__HAL_ADC_ENABLE(hadc);
/* Delay for ADC stabilization time */
/* Compute number of CPU cycles to wait for */
wait_loop_index = (ADC_STAB_DELAY_US * (SystemCoreClock / 1000000U));
while(wait_loop_index != 0U)
{
wait_loop_index--;
}
/* Get tick count */
tickstart = HAL_GetTick();
/* Wait for ADC effectively enabled */
while(ADC_IS_ENABLE(hadc) == RESET)
{
if((HAL_GetTick() - tickstart) > ADC_ENABLE_TIMEOUT)
{
/* New check to avoid false timeout detection in case of preemption */
if(ADC_IS_ENABLE(hadc) == RESET)
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);
/* Set ADC error code to ADC IP internal error */
SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);
/* Process unlocked */
__HAL_UNLOCK(hadc);
return HAL_ERROR;
}
}
}
}
/* Return HAL status */
return HAL_OK;
}
/**
* @brief Stop ADC conversion and disable the selected ADC
* @note Prerequisite condition to use this function: ADC conversions must be
* stopped to disable the ADC.
* @param hadc: ADC handle
* @retval HAL status.
*/
HAL_StatusTypeDef ADC_ConversionStop_Disable(ADC_HandleTypeDef* hadc)
{
uint32_t tickstart = 0U;
/* Verification if ADC is not already disabled */
if (ADC_IS_ENABLE(hadc) != RESET)
{
/* Disable the ADC peripheral */
__HAL_ADC_DISABLE(hadc);
/* Get tick count */
tickstart = HAL_GetTick();
/* Wait for ADC effectively disabled */
while(ADC_IS_ENABLE(hadc) != RESET)
{
if((HAL_GetTick() - tickstart) > ADC_DISABLE_TIMEOUT)
{
/* New check to avoid false timeout detection in case of preemption */
if(ADC_IS_ENABLE(hadc) != RESET)
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);
/* Set ADC error code to ADC IP internal error */
SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);
return HAL_ERROR;
}
}
}
}
/* Return HAL status */
return HAL_OK;
}
/**
* @brief DMA transfer complete callback.
* @param hdma: pointer to DMA handle.
* @retval None
*/
void ADC_DMAConvCplt(DMA_HandleTypeDef *hdma)
{
/* Retrieve ADC handle corresponding to current DMA handle */
ADC_HandleTypeDef* hadc = ( ADC_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
/* Update state machine on conversion status if not in error state */
if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL | HAL_ADC_STATE_ERROR_DMA))
{
/* Update ADC state machine */
SET_BIT(hadc->State, HAL_ADC_STATE_REG_EOC);
/* Determine whether any further conversion upcoming on group regular */
/* by external trigger, continuous mode or scan sequence on going. */
/* Note: On STM32F1 devices, in case of sequencer enabled */
/* (several ranks selected), end of conversion flag is raised */
/* at the end of the sequence. */
if(ADC_IS_SOFTWARE_START_REGULAR(hadc) &&
(hadc->Init.ContinuousConvMode == DISABLE) )
{
/* Set ADC state */
CLEAR_BIT(hadc->State, HAL_ADC_STATE_REG_BUSY);
if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_INJ_BUSY))
{
SET_BIT(hadc->State, HAL_ADC_STATE_READY);
}
}
/* Conversion complete callback */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
hadc->ConvCpltCallback(hadc);
#else
HAL_ADC_ConvCpltCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
}
else
{
/* Call DMA error callback */
hadc->DMA_Handle->XferErrorCallback(hdma);
}
}
/**
* @brief DMA half transfer complete callback.
* @param hdma: pointer to DMA handle.
* @retval None
*/
void ADC_DMAHalfConvCplt(DMA_HandleTypeDef *hdma)
{
/* Retrieve ADC handle corresponding to current DMA handle */
ADC_HandleTypeDef* hadc = ( ADC_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
/* Half conversion callback */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
hadc->ConvHalfCpltCallback(hadc);
#else
HAL_ADC_ConvHalfCpltCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
}
/**
* @brief DMA error callback
* @param hdma: pointer to DMA handle.
* @retval None
*/
void ADC_DMAError(DMA_HandleTypeDef *hdma)
{
/* Retrieve ADC handle corresponding to current DMA handle */
ADC_HandleTypeDef* hadc = ( ADC_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;
/* Set ADC state */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_DMA);
/* Set ADC error code to DMA error */
SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_DMA);
/* Error callback */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
hadc->ErrorCallback(hadc);
#else
HAL_ADC_ErrorCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
}
/**
* @}
*/
#endif /* HAL_ADC_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,1325 @@
/**
******************************************************************************
* @file stm32f1xx_hal_adc_ex.c
* @author MCD Application Team
* @brief This file provides firmware functions to manage the following
* functionalities of the Analog to Digital Convertor (ADC)
* peripheral:
* + Peripheral Control functions
* Other functions (generic functions) are available in file
* "stm32f1xx_hal_adc.c".
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
[..]
(@) Sections "ADC peripheral features" and "How to use this driver" are
available in file of generic functions "stm32f1xx_hal_adc.c".
[..]
@endverbatim
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup ADCEx ADCEx
* @brief ADC Extension HAL module driver
* @{
*/
#ifdef HAL_ADC_MODULE_ENABLED
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup ADCEx_Private_Constants ADCEx Private Constants
* @{
*/
/* Delay for ADC calibration: */
/* Hardware prerequisite before starting a calibration: the ADC must have */
/* been in power-on state for at least two ADC clock cycles. */
/* Unit: ADC clock cycles */
#define ADC_PRECALIBRATION_DELAY_ADCCLOCKCYCLES 2U
/* Timeout value for ADC calibration */
/* Value defined to be higher than worst cases: low clocks freq, */
/* maximum prescaler. */
/* Ex of profile low frequency : Clock source at 0.1 MHz, ADC clock */
/* prescaler 4, sampling time 12.5 ADC clock cycles, resolution 12 bits. */
/* Unit: ms */
#define ADC_CALIBRATION_TIMEOUT 10U
/* Delay for temperature sensor stabilization time. */
/* Maximum delay is 10us (refer to device datasheet, parameter tSTART). */
/* Unit: us */
#define ADC_TEMPSENSOR_DELAY_US 10U
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup ADCEx_Exported_Functions ADCEx Exported Functions
* @{
*/
/** @defgroup ADCEx_Exported_Functions_Group1 Extended Extended IO operation functions
* @brief Extended Extended Input and Output operation functions
*
@verbatim
===============================================================================
##### IO operation functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Start conversion of injected group.
(+) Stop conversion of injected group.
(+) Poll for conversion complete on injected group.
(+) Get result of injected channel conversion.
(+) Start conversion of injected group and enable interruptions.
(+) Stop conversion of injected group and disable interruptions.
(+) Start multimode and enable DMA transfer.
(+) Stop multimode and disable ADC DMA transfer.
(+) Get result of multimode conversion.
(+) Perform the ADC self-calibration for single or differential ending.
(+) Get calibration factors for single or differential ending.
(+) Set calibration factors for single or differential ending.
@endverbatim
* @{
*/
/**
* @brief Perform an ADC automatic self-calibration
* Calibration prerequisite: ADC must be disabled (execute this
* function before HAL_ADC_Start() or after HAL_ADC_Stop() ).
* During calibration process, ADC is enabled. ADC is let enabled at
* the completion of this function.
* @param hadc: ADC handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ADCEx_Calibration_Start(ADC_HandleTypeDef* hadc)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
uint32_t tickstart;
__IO uint32_t wait_loop_index = 0U;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
/* Process locked */
__HAL_LOCK(hadc);
/* 1. Disable ADC peripheral */
tmp_hal_status = ADC_ConversionStop_Disable(hadc);
/* 2. Calibration prerequisite delay before starting the calibration. */
/* - ADC must be enabled for at least two ADC clock cycles */
tmp_hal_status = ADC_Enable(hadc);
/* Check if ADC is effectively enabled */
if (tmp_hal_status == HAL_OK)
{
/* Set ADC state */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_REG_BUSY | HAL_ADC_STATE_INJ_BUSY,
HAL_ADC_STATE_BUSY_INTERNAL);
/* Hardware prerequisite: delay before starting the calibration. */
/* - Computation of CPU clock cycles corresponding to ADC clock cycles. */
/* - Wait for the expected ADC clock cycles delay */
wait_loop_index = ((SystemCoreClock
/ HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_ADC))
* ADC_PRECALIBRATION_DELAY_ADCCLOCKCYCLES );
while(wait_loop_index != 0U)
{
wait_loop_index--;
}
/* 3. Resets ADC calibration registers */
SET_BIT(hadc->Instance->CR2, ADC_CR2_RSTCAL);
tickstart = HAL_GetTick();
/* Wait for calibration reset completion */
while(HAL_IS_BIT_SET(hadc->Instance->CR2, ADC_CR2_RSTCAL))
{
if((HAL_GetTick() - tickstart) > ADC_CALIBRATION_TIMEOUT)
{
/* New check to avoid false timeout detection in case of preemption */
if(HAL_IS_BIT_SET(hadc->Instance->CR2, ADC_CR2_RSTCAL))
{
/* Update ADC state machine to error */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_BUSY_INTERNAL,
HAL_ADC_STATE_ERROR_INTERNAL);
/* Process unlocked */
__HAL_UNLOCK(hadc);
return HAL_ERROR;
}
}
}
/* 4. Start ADC calibration */
SET_BIT(hadc->Instance->CR2, ADC_CR2_CAL);
tickstart = HAL_GetTick();
/* Wait for calibration completion */
while(HAL_IS_BIT_SET(hadc->Instance->CR2, ADC_CR2_CAL))
{
if((HAL_GetTick() - tickstart) > ADC_CALIBRATION_TIMEOUT)
{
/* New check to avoid false timeout detection in case of preemption */
if(HAL_IS_BIT_SET(hadc->Instance->CR2, ADC_CR2_CAL))
{
/* Update ADC state machine to error */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_BUSY_INTERNAL,
HAL_ADC_STATE_ERROR_INTERNAL);
/* Process unlocked */
__HAL_UNLOCK(hadc);
return HAL_ERROR;
}
}
}
/* Set ADC state */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_BUSY_INTERNAL,
HAL_ADC_STATE_READY);
}
/* Process unlocked */
__HAL_UNLOCK(hadc);
/* Return function status */
return tmp_hal_status;
}
/**
* @brief Enables ADC, starts conversion of injected group.
* Interruptions enabled in this function: None.
* @param hadc: ADC handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ADCEx_InjectedStart(ADC_HandleTypeDef* hadc)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
/* Process locked */
__HAL_LOCK(hadc);
/* Enable the ADC peripheral */
tmp_hal_status = ADC_Enable(hadc);
/* Start conversion if ADC is effectively enabled */
if (tmp_hal_status == HAL_OK)
{
/* Set ADC state */
/* - Clear state bitfield related to injected group conversion results */
/* - Set state bitfield related to injected operation */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_READY | HAL_ADC_STATE_INJ_EOC,
HAL_ADC_STATE_INJ_BUSY);
/* Case of independent mode or multimode (for devices with several ADCs): */
/* Set multimode state. */
if (ADC_NONMULTIMODE_OR_MULTIMODEMASTER(hadc))
{
CLEAR_BIT(hadc->State, HAL_ADC_STATE_MULTIMODE_SLAVE);
}
else
{
SET_BIT(hadc->State, HAL_ADC_STATE_MULTIMODE_SLAVE);
}
/* Check if a regular conversion is ongoing */
/* Note: On this device, there is no ADC error code fields related to */
/* conversions on group injected only. In case of conversion on */
/* going on group regular, no error code is reset. */
if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_REG_BUSY))
{
/* Reset ADC all error code fields */
ADC_CLEAR_ERRORCODE(hadc);
}
/* Process unlocked */
/* Unlock before starting ADC conversions: in case of potential */
/* interruption, to let the process to ADC IRQ Handler. */
__HAL_UNLOCK(hadc);
/* Clear injected group conversion flag */
/* (To ensure of no unknown state from potential previous ADC operations) */
__HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_JEOC);
/* Enable conversion of injected group. */
/* If software start has been selected, conversion starts immediately. */
/* If external trigger has been selected, conversion will start at next */
/* trigger event. */
/* If automatic injected conversion is enabled, conversion will start */
/* after next regular group conversion. */
/* Case of multimode enabled (for devices with several ADCs): if ADC is */
/* slave, ADC is enabled only (conversion is not started). If ADC is */
/* master, ADC is enabled and conversion is started. */
if (HAL_IS_BIT_CLR(hadc->Instance->CR1, ADC_CR1_JAUTO))
{
if (ADC_IS_SOFTWARE_START_INJECTED(hadc) &&
ADC_NONMULTIMODE_OR_MULTIMODEMASTER(hadc) )
{
/* Start ADC conversion on injected group with SW start */
SET_BIT(hadc->Instance->CR2, (ADC_CR2_JSWSTART | ADC_CR2_JEXTTRIG));
}
else
{
/* Start ADC conversion on injected group with external trigger */
SET_BIT(hadc->Instance->CR2, ADC_CR2_JEXTTRIG);
}
}
}
else
{
/* Process unlocked */
__HAL_UNLOCK(hadc);
}
/* Return function status */
return tmp_hal_status;
}
/**
* @brief Stop conversion of injected channels. Disable ADC peripheral if
* no regular conversion is on going.
* @note If ADC must be disabled and if conversion is on going on
* regular group, function HAL_ADC_Stop must be used to stop both
* injected and regular groups, and disable the ADC.
* @note If injected group mode auto-injection is enabled,
* function HAL_ADC_Stop must be used.
* @note In case of auto-injection mode, HAL_ADC_Stop must be used.
* @param hadc: ADC handle
* @retval None
*/
HAL_StatusTypeDef HAL_ADCEx_InjectedStop(ADC_HandleTypeDef* hadc)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
/* Process locked */
__HAL_LOCK(hadc);
/* Stop potential conversion and disable ADC peripheral */
/* Conditioned to: */
/* - No conversion on the other group (regular group) is intended to */
/* continue (injected and regular groups stop conversion and ADC disable */
/* are common) */
/* - In case of auto-injection mode, HAL_ADC_Stop must be used. */
if(((hadc->State & HAL_ADC_STATE_REG_BUSY) == RESET) &&
HAL_IS_BIT_CLR(hadc->Instance->CR1, ADC_CR1_JAUTO) )
{
/* Stop potential conversion on going, on regular and injected groups */
/* Disable ADC peripheral */
tmp_hal_status = ADC_ConversionStop_Disable(hadc);
/* Check if ADC is effectively disabled */
if (tmp_hal_status == HAL_OK)
{
/* Set ADC state */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_REG_BUSY | HAL_ADC_STATE_INJ_BUSY,
HAL_ADC_STATE_READY);
}
}
else
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
tmp_hal_status = HAL_ERROR;
}
/* Process unlocked */
__HAL_UNLOCK(hadc);
/* Return function status */
return tmp_hal_status;
}
/**
* @brief Wait for injected group conversion to be completed.
* @param hadc: ADC handle
* @param Timeout: Timeout value in millisecond.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ADCEx_InjectedPollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout)
{
uint32_t tickstart;
/* Variables for polling in case of scan mode enabled and polling for each */
/* conversion. */
__IO uint32_t Conversion_Timeout_CPU_cycles = 0U;
uint32_t Conversion_Timeout_CPU_cycles_max = 0U;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
/* Get timeout */
tickstart = HAL_GetTick();
/* Polling for end of conversion: differentiation if single/sequence */
/* conversion. */
/* For injected group, flag JEOC is set only at the end of the sequence, */
/* not for each conversion within the sequence. */
/* - If single conversion for injected group (scan mode disabled or */
/* InjectedNbrOfConversion ==1), flag JEOC is used to determine the */
/* conversion completion. */
/* - If sequence conversion for injected group (scan mode enabled and */
/* InjectedNbrOfConversion >=2), flag JEOC is set only at the end of the */
/* sequence. */
/* To poll for each conversion, the maximum conversion time is computed */
/* from ADC conversion time (selected sampling time + conversion time of */
/* 12.5 ADC clock cycles) and APB2/ADC clock prescalers (depending on */
/* settings, conversion time range can be from 28 to 32256 CPU cycles). */
/* As flag JEOC is not set after each conversion, no timeout status can */
/* be set. */
if ((hadc->Instance->JSQR & ADC_JSQR_JL) == RESET)
{
/* Wait until End of Conversion flag is raised */
while(HAL_IS_BIT_CLR(hadc->Instance->SR, ADC_FLAG_JEOC))
{
/* Check if timeout is disabled (set to infinite wait) */
if(Timeout != HAL_MAX_DELAY)
{
if((Timeout == 0U) || ((HAL_GetTick() - tickstart ) > Timeout))
{
/* New check to avoid false timeout detection in case of preemption */
if(HAL_IS_BIT_CLR(hadc->Instance->SR, ADC_FLAG_JEOC))
{
/* Update ADC state machine to timeout */
SET_BIT(hadc->State, HAL_ADC_STATE_TIMEOUT);
/* Process unlocked */
__HAL_UNLOCK(hadc);
return HAL_TIMEOUT;
}
}
}
}
}
else
{
/* Replace polling by wait for maximum conversion time */
/* - Computation of CPU clock cycles corresponding to ADC clock cycles */
/* and ADC maximum conversion cycles on all channels. */
/* - Wait for the expected ADC clock cycles delay */
Conversion_Timeout_CPU_cycles_max = ((SystemCoreClock
/ HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_ADC))
* ADC_CONVCYCLES_MAX_RANGE(hadc) );
while(Conversion_Timeout_CPU_cycles < Conversion_Timeout_CPU_cycles_max)
{
/* Check if timeout is disabled (set to infinite wait) */
if(Timeout != HAL_MAX_DELAY)
{
if((Timeout == 0)||((HAL_GetTick() - tickstart ) > Timeout))
{
/* New check to avoid false timeout detection in case of preemption */
if(Conversion_Timeout_CPU_cycles < Conversion_Timeout_CPU_cycles_max)
{
/* Update ADC state machine to timeout */
SET_BIT(hadc->State, HAL_ADC_STATE_TIMEOUT);
/* Process unlocked */
__HAL_UNLOCK(hadc);
return HAL_TIMEOUT;
}
}
}
Conversion_Timeout_CPU_cycles ++;
}
}
/* Clear injected group conversion flag */
/* Note: On STM32F1 ADC, clear regular conversion flag raised */
/* simultaneously. */
__HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_JSTRT | ADC_FLAG_JEOC | ADC_FLAG_EOC);
/* Update ADC state machine */
SET_BIT(hadc->State, HAL_ADC_STATE_INJ_EOC);
/* Determine whether any further conversion upcoming on group injected */
/* by external trigger or by automatic injected conversion */
/* from group regular. */
if(ADC_IS_SOFTWARE_START_INJECTED(hadc) ||
(HAL_IS_BIT_CLR(hadc->Instance->CR1, ADC_CR1_JAUTO) &&
(ADC_IS_SOFTWARE_START_REGULAR(hadc) &&
(hadc->Init.ContinuousConvMode == DISABLE) ) ) )
{
/* Set ADC state */
CLEAR_BIT(hadc->State, HAL_ADC_STATE_INJ_BUSY);
if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_REG_BUSY))
{
SET_BIT(hadc->State, HAL_ADC_STATE_READY);
}
}
/* Return ADC state */
return HAL_OK;
}
/**
* @brief Enables ADC, starts conversion of injected group with interruption.
* - JEOC (end of conversion of injected group)
* Each of these interruptions has its dedicated callback function.
* @param hadc: ADC handle
* @retval HAL status.
*/
HAL_StatusTypeDef HAL_ADCEx_InjectedStart_IT(ADC_HandleTypeDef* hadc)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
/* Process locked */
__HAL_LOCK(hadc);
/* Enable the ADC peripheral */
tmp_hal_status = ADC_Enable(hadc);
/* Start conversion if ADC is effectively enabled */
if (tmp_hal_status == HAL_OK)
{
/* Set ADC state */
/* - Clear state bitfield related to injected group conversion results */
/* - Set state bitfield related to injected operation */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_READY | HAL_ADC_STATE_INJ_EOC,
HAL_ADC_STATE_INJ_BUSY);
/* Case of independent mode or multimode (for devices with several ADCs): */
/* Set multimode state. */
if (ADC_NONMULTIMODE_OR_MULTIMODEMASTER(hadc))
{
CLEAR_BIT(hadc->State, HAL_ADC_STATE_MULTIMODE_SLAVE);
}
else
{
SET_BIT(hadc->State, HAL_ADC_STATE_MULTIMODE_SLAVE);
}
/* Check if a regular conversion is ongoing */
/* Note: On this device, there is no ADC error code fields related to */
/* conversions on group injected only. In case of conversion on */
/* going on group regular, no error code is reset. */
if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_REG_BUSY))
{
/* Reset ADC all error code fields */
ADC_CLEAR_ERRORCODE(hadc);
}
/* Process unlocked */
/* Unlock before starting ADC conversions: in case of potential */
/* interruption, to let the process to ADC IRQ Handler. */
__HAL_UNLOCK(hadc);
/* Clear injected group conversion flag */
/* (To ensure of no unknown state from potential previous ADC operations) */
__HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_JEOC);
/* Enable end of conversion interrupt for injected channels */
__HAL_ADC_ENABLE_IT(hadc, ADC_IT_JEOC);
/* Start conversion of injected group if software start has been selected */
/* and if automatic injected conversion is disabled. */
/* If external trigger has been selected, conversion will start at next */
/* trigger event. */
/* If automatic injected conversion is enabled, conversion will start */
/* after next regular group conversion. */
if (HAL_IS_BIT_CLR(hadc->Instance->CR1, ADC_CR1_JAUTO))
{
if (ADC_IS_SOFTWARE_START_INJECTED(hadc) &&
ADC_NONMULTIMODE_OR_MULTIMODEMASTER(hadc) )
{
/* Start ADC conversion on injected group with SW start */
SET_BIT(hadc->Instance->CR2, (ADC_CR2_JSWSTART | ADC_CR2_JEXTTRIG));
}
else
{
/* Start ADC conversion on injected group with external trigger */
SET_BIT(hadc->Instance->CR2, ADC_CR2_JEXTTRIG);
}
}
}
else
{
/* Process unlocked */
__HAL_UNLOCK(hadc);
}
/* Return function status */
return tmp_hal_status;
}
/**
* @brief Stop conversion of injected channels, disable interruption of
* end-of-conversion. Disable ADC peripheral if no regular conversion
* is on going.
* @note If ADC must be disabled and if conversion is on going on
* regular group, function HAL_ADC_Stop must be used to stop both
* injected and regular groups, and disable the ADC.
* @note If injected group mode auto-injection is enabled,
* function HAL_ADC_Stop must be used.
* @param hadc: ADC handle
* @retval None
*/
HAL_StatusTypeDef HAL_ADCEx_InjectedStop_IT(ADC_HandleTypeDef* hadc)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
/* Process locked */
__HAL_LOCK(hadc);
/* Stop potential conversion and disable ADC peripheral */
/* Conditioned to: */
/* - No conversion on the other group (regular group) is intended to */
/* continue (injected and regular groups stop conversion and ADC disable */
/* are common) */
/* - In case of auto-injection mode, HAL_ADC_Stop must be used. */
if(((hadc->State & HAL_ADC_STATE_REG_BUSY) == RESET) &&
HAL_IS_BIT_CLR(hadc->Instance->CR1, ADC_CR1_JAUTO) )
{
/* Stop potential conversion on going, on regular and injected groups */
/* Disable ADC peripheral */
tmp_hal_status = ADC_ConversionStop_Disable(hadc);
/* Check if ADC is effectively disabled */
if (tmp_hal_status == HAL_OK)
{
/* Disable ADC end of conversion interrupt for injected channels */
__HAL_ADC_DISABLE_IT(hadc, ADC_IT_JEOC);
/* Set ADC state */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_REG_BUSY | HAL_ADC_STATE_INJ_BUSY,
HAL_ADC_STATE_READY);
}
}
else
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
tmp_hal_status = HAL_ERROR;
}
/* Process unlocked */
__HAL_UNLOCK(hadc);
/* Return function status */
return tmp_hal_status;
}
#if defined (STM32F103x6) || defined (STM32F103xB) || defined (STM32F105xC) || defined (STM32F107xC) || defined (STM32F103xE) || defined (STM32F103xG)
/**
* @brief Enables ADC, starts conversion of regular group and transfers result
* through DMA.
* Multimode must have been previously configured using
* HAL_ADCEx_MultiModeConfigChannel() function.
* Interruptions enabled in this function:
* - DMA transfer complete
* - DMA half transfer
* Each of these interruptions has its dedicated callback function.
* @note: On STM32F1 devices, ADC slave regular group must be configured
* with conversion trigger ADC_SOFTWARE_START.
* @note: ADC slave can be enabled preliminarily using single-mode
* HAL_ADC_Start() function.
* @param hadc: ADC handle of ADC master (handle of ADC slave must not be used)
* @param pData: The destination Buffer address.
* @param Length: The length of data to be transferred from ADC peripheral to memory.
* @retval None
*/
HAL_StatusTypeDef HAL_ADCEx_MultiModeStart_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
ADC_HandleTypeDef tmphadcSlave={0};
/* Check the parameters */
assert_param(IS_ADC_MULTIMODE_MASTER_INSTANCE(hadc->Instance));
assert_param(IS_FUNCTIONAL_STATE(hadc->Init.ContinuousConvMode));
/* Process locked */
__HAL_LOCK(hadc);
/* Set a temporary handle of the ADC slave associated to the ADC master */
ADC_MULTI_SLAVE(hadc, &tmphadcSlave);
/* On STM32F1 devices, ADC slave regular group must be configured with */
/* conversion trigger ADC_SOFTWARE_START. */
/* Note: External trigger of ADC slave must be enabled, it is already done */
/* into function "HAL_ADC_Init()". */
if(!ADC_IS_SOFTWARE_START_REGULAR(&tmphadcSlave))
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
/* Process unlocked */
__HAL_UNLOCK(hadc);
return HAL_ERROR;
}
/* Enable the ADC peripherals: master and slave (in case if not already */
/* enabled previously) */
tmp_hal_status = ADC_Enable(hadc);
if (tmp_hal_status == HAL_OK)
{
tmp_hal_status = ADC_Enable(&tmphadcSlave);
}
/* Start conversion if all ADCs of multimode are effectively enabled */
if (tmp_hal_status == HAL_OK)
{
/* Set ADC state (ADC master) */
/* - Clear state bitfield related to regular group conversion results */
/* - Set state bitfield related to regular operation */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_READY | HAL_ADC_STATE_REG_EOC | HAL_ADC_STATE_MULTIMODE_SLAVE,
HAL_ADC_STATE_REG_BUSY);
/* If conversions on group regular are also triggering group injected, */
/* update ADC state. */
if (READ_BIT(hadc->Instance->CR1, ADC_CR1_JAUTO) != RESET)
{
ADC_STATE_CLR_SET(hadc->State, HAL_ADC_STATE_INJ_EOC, HAL_ADC_STATE_INJ_BUSY);
}
/* Process unlocked */
/* Unlock before starting ADC conversions: in case of potential */
/* interruption, to let the process to ADC IRQ Handler. */
__HAL_UNLOCK(hadc);
/* Set ADC error code to none */
ADC_CLEAR_ERRORCODE(hadc);
/* Set the DMA transfer complete callback */
hadc->DMA_Handle->XferCpltCallback = ADC_DMAConvCplt;
/* Set the DMA half transfer complete callback */
hadc->DMA_Handle->XferHalfCpltCallback = ADC_DMAHalfConvCplt;
/* Set the DMA error callback */
hadc->DMA_Handle->XferErrorCallback = ADC_DMAError;
/* Manage ADC and DMA start: ADC overrun interruption, DMA start, ADC */
/* start (in case of SW start): */
/* Clear regular group conversion flag and overrun flag */
/* (To ensure of no unknown state from potential previous ADC operations) */
__HAL_ADC_CLEAR_FLAG(hadc, ADC_FLAG_EOC);
/* Enable ADC DMA mode of ADC master */
SET_BIT(hadc->Instance->CR2, ADC_CR2_DMA);
/* Start the DMA channel */
HAL_DMA_Start_IT(hadc->DMA_Handle, (uint32_t)&hadc->Instance->DR, (uint32_t)pData, Length);
/* Start conversion of regular group if software start has been selected. */
/* If external trigger has been selected, conversion will start at next */
/* trigger event. */
/* Note: Alternate trigger for single conversion could be to force an */
/* additional set of bit ADON "hadc->Instance->CR2 |= ADC_CR2_ADON;"*/
if (ADC_IS_SOFTWARE_START_REGULAR(hadc))
{
/* Start ADC conversion on regular group with SW start */
SET_BIT(hadc->Instance->CR2, (ADC_CR2_SWSTART | ADC_CR2_EXTTRIG));
}
else
{
/* Start ADC conversion on regular group with external trigger */
SET_BIT(hadc->Instance->CR2, ADC_CR2_EXTTRIG);
}
}
else
{
/* Process unlocked */
__HAL_UNLOCK(hadc);
}
/* Return function status */
return tmp_hal_status;
}
/**
* @brief Stop ADC conversion of regular group (and injected channels in
* case of auto_injection mode), disable ADC DMA transfer, disable
* ADC peripheral.
* @note Multimode is kept enabled after this function. To disable multimode
* (set with HAL_ADCEx_MultiModeConfigChannel(), ADC must be
* reinitialized using HAL_ADC_Init() or HAL_ADC_ReInit().
* @note In case of DMA configured in circular mode, function
* HAL_ADC_Stop_DMA must be called after this function with handle of
* ADC slave, to properly disable the DMA channel.
* @param hadc: ADC handle of ADC master (handle of ADC slave must not be used)
* @retval None
*/
HAL_StatusTypeDef HAL_ADCEx_MultiModeStop_DMA(ADC_HandleTypeDef* hadc)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
ADC_HandleTypeDef tmphadcSlave={0};
/* Check the parameters */
assert_param(IS_ADC_MULTIMODE_MASTER_INSTANCE(hadc->Instance));
/* Process locked */
__HAL_LOCK(hadc);
/* Stop potential conversion on going, on regular and injected groups */
/* Disable ADC master peripheral */
tmp_hal_status = ADC_ConversionStop_Disable(hadc);
/* Check if ADC is effectively disabled */
if(tmp_hal_status == HAL_OK)
{
/* Set a temporary handle of the ADC slave associated to the ADC master */
ADC_MULTI_SLAVE(hadc, &tmphadcSlave);
/* Disable ADC slave peripheral */
tmp_hal_status = ADC_ConversionStop_Disable(&tmphadcSlave);
/* Check if ADC is effectively disabled */
if(tmp_hal_status != HAL_OK)
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);
/* Process unlocked */
__HAL_UNLOCK(hadc);
return HAL_ERROR;
}
/* Disable ADC DMA mode */
CLEAR_BIT(hadc->Instance->CR2, ADC_CR2_DMA);
/* Reset configuration of ADC DMA continuous request for dual mode */
CLEAR_BIT(hadc->Instance->CR1, ADC_CR1_DUALMOD);
/* Disable the DMA channel (in case of DMA in circular mode or stop while */
/* while DMA transfer is on going) */
tmp_hal_status = HAL_DMA_Abort(hadc->DMA_Handle);
/* Change ADC state (ADC master) */
ADC_STATE_CLR_SET(hadc->State,
HAL_ADC_STATE_REG_BUSY | HAL_ADC_STATE_INJ_BUSY,
HAL_ADC_STATE_READY);
}
/* Process unlocked */
__HAL_UNLOCK(hadc);
/* Return function status */
return tmp_hal_status;
}
#endif /* defined STM32F103x6 || defined STM32F103xB || defined STM32F105xC || defined STM32F107xC || defined STM32F103xE || defined STM32F103xG */
/**
* @brief Get ADC injected group conversion result.
* @note Reading register JDRx automatically clears ADC flag JEOC
* (ADC group injected end of unitary conversion).
* @note This function does not clear ADC flag JEOS
* (ADC group injected end of sequence conversion)
* Occurrence of flag JEOS rising:
* - If sequencer is composed of 1 rank, flag JEOS is equivalent
* to flag JEOC.
* - If sequencer is composed of several ranks, during the scan
* sequence flag JEOC only is raised, at the end of the scan sequence
* both flags JEOC and EOS are raised.
* Flag JEOS must not be cleared by this function because
* it would not be compliant with low power features
* (feature low power auto-wait, not available on all STM32 families).
* To clear this flag, either use function:
* in programming model IT: @ref HAL_ADC_IRQHandler(), in programming
* model polling: @ref HAL_ADCEx_InjectedPollForConversion()
* or @ref __HAL_ADC_CLEAR_FLAG(&hadc, ADC_FLAG_JEOS).
* @param hadc: ADC handle
* @param InjectedRank: the converted ADC injected rank.
* This parameter can be one of the following values:
* @arg ADC_INJECTED_RANK_1: Injected Channel1 selected
* @arg ADC_INJECTED_RANK_2: Injected Channel2 selected
* @arg ADC_INJECTED_RANK_3: Injected Channel3 selected
* @arg ADC_INJECTED_RANK_4: Injected Channel4 selected
* @retval ADC group injected conversion data
*/
uint32_t HAL_ADCEx_InjectedGetValue(ADC_HandleTypeDef* hadc, uint32_t InjectedRank)
{
uint32_t tmp_jdr = 0U;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
assert_param(IS_ADC_INJECTED_RANK(InjectedRank));
/* Get ADC converted value */
switch(InjectedRank)
{
case ADC_INJECTED_RANK_4:
tmp_jdr = hadc->Instance->JDR4;
break;
case ADC_INJECTED_RANK_3:
tmp_jdr = hadc->Instance->JDR3;
break;
case ADC_INJECTED_RANK_2:
tmp_jdr = hadc->Instance->JDR2;
break;
case ADC_INJECTED_RANK_1:
default:
tmp_jdr = hadc->Instance->JDR1;
break;
}
/* Return ADC converted value */
return tmp_jdr;
}
#if defined (STM32F103x6) || defined (STM32F103xB) || defined (STM32F105xC) || defined (STM32F107xC) || defined (STM32F103xE) || defined (STM32F103xG)
/**
* @brief Returns the last ADC Master&Slave regular conversions results data
* in the selected multi mode.
* @param hadc: ADC handle of ADC master (handle of ADC slave must not be used)
* @retval The converted data value.
*/
uint32_t HAL_ADCEx_MultiModeGetValue(ADC_HandleTypeDef* hadc)
{
uint32_t tmpDR = 0U;
/* Check the parameters */
assert_param(IS_ADC_MULTIMODE_MASTER_INSTANCE(hadc->Instance));
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
/* Note: EOC flag is not cleared here by software because automatically */
/* cleared by hardware when reading register DR. */
/* On STM32F1 devices, ADC1 data register DR contains ADC2 conversions */
/* only if ADC1 DMA mode is enabled. */
tmpDR = hadc->Instance->DR;
if (HAL_IS_BIT_CLR(ADC1->CR2, ADC_CR2_DMA))
{
tmpDR |= (ADC2->DR << 16U);
}
/* Return ADC converted value */
return tmpDR;
}
#endif /* defined STM32F103x6 || defined STM32F103xB || defined STM32F105xC || defined STM32F107xC || defined STM32F103xE || defined STM32F103xG */
/**
* @brief Injected conversion complete callback in non blocking mode
* @param hadc: ADC handle
* @retval None
*/
__weak void HAL_ADCEx_InjectedConvCpltCallback(ADC_HandleTypeDef* hadc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hadc);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_ADCEx_InjectedConvCpltCallback could be implemented in the user file
*/
}
/**
* @}
*/
/** @defgroup ADCEx_Exported_Functions_Group2 Extended Peripheral Control functions
* @brief Extended Peripheral Control functions
*
@verbatim
===============================================================================
##### Peripheral Control functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Configure channels on injected group
(+) Configure multimode
@endverbatim
* @{
*/
/**
* @brief Configures the ADC injected group and the selected channel to be
* linked to the injected group.
* @note Possibility to update parameters on the fly:
* This function initializes injected group, following calls to this
* function can be used to reconfigure some parameters of structure
* "ADC_InjectionConfTypeDef" on the fly, without resetting the ADC.
* The setting of these parameters is conditioned to ADC state:
* this function must be called when ADC is not under conversion.
* @param hadc: ADC handle
* @param sConfigInjected: Structure of ADC injected group and ADC channel for
* injected group.
* @retval None
*/
HAL_StatusTypeDef HAL_ADCEx_InjectedConfigChannel(ADC_HandleTypeDef* hadc, ADC_InjectionConfTypeDef* sConfigInjected)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
__IO uint32_t wait_loop_index = 0U;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
assert_param(IS_ADC_CHANNEL(sConfigInjected->InjectedChannel));
assert_param(IS_ADC_SAMPLE_TIME(sConfigInjected->InjectedSamplingTime));
assert_param(IS_FUNCTIONAL_STATE(sConfigInjected->AutoInjectedConv));
assert_param(IS_ADC_EXTTRIGINJEC(sConfigInjected->ExternalTrigInjecConv));
assert_param(IS_ADC_RANGE(sConfigInjected->InjectedOffset));
if(hadc->Init.ScanConvMode != ADC_SCAN_DISABLE)
{
assert_param(IS_ADC_INJECTED_RANK(sConfigInjected->InjectedRank));
assert_param(IS_ADC_INJECTED_NB_CONV(sConfigInjected->InjectedNbrOfConversion));
assert_param(IS_FUNCTIONAL_STATE(sConfigInjected->InjectedDiscontinuousConvMode));
}
/* Process locked */
__HAL_LOCK(hadc);
/* Configuration of injected group sequencer: */
/* - if scan mode is disabled, injected channels sequence length is set to */
/* 0x00: 1 channel converted (channel on regular rank 1) */
/* Parameter "InjectedNbrOfConversion" is discarded. */
/* Note: Scan mode is present by hardware on this device and, if */
/* disabled, discards automatically nb of conversions. Anyway, nb of */
/* conversions is forced to 0x00 for alignment over all STM32 devices. */
/* - if scan mode is enabled, injected channels sequence length is set to */
/* parameter "InjectedNbrOfConversion". */
if (hadc->Init.ScanConvMode == ADC_SCAN_DISABLE)
{
if (sConfigInjected->InjectedRank == ADC_INJECTED_RANK_1)
{
/* Clear the old SQx bits for all injected ranks */
MODIFY_REG(hadc->Instance->JSQR ,
ADC_JSQR_JL |
ADC_JSQR_JSQ4 |
ADC_JSQR_JSQ3 |
ADC_JSQR_JSQ2 |
ADC_JSQR_JSQ1 ,
ADC_JSQR_RK_JL(sConfigInjected->InjectedChannel,
ADC_INJECTED_RANK_1,
0x01U));
}
/* If another injected rank than rank1 was intended to be set, and could */
/* not due to ScanConvMode disabled, error is reported. */
else
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
tmp_hal_status = HAL_ERROR;
}
}
else
{
/* Since injected channels rank conv. order depends on total number of */
/* injected conversions, selected rank must be below or equal to total */
/* number of injected conversions to be updated. */
if (sConfigInjected->InjectedRank <= sConfigInjected->InjectedNbrOfConversion)
{
/* Clear the old SQx bits for the selected rank */
/* Set the SQx bits for the selected rank */
MODIFY_REG(hadc->Instance->JSQR ,
ADC_JSQR_JL |
ADC_JSQR_RK_JL(ADC_JSQR_JSQ1,
sConfigInjected->InjectedRank,
sConfigInjected->InjectedNbrOfConversion) ,
ADC_JSQR_JL_SHIFT(sConfigInjected->InjectedNbrOfConversion) |
ADC_JSQR_RK_JL(sConfigInjected->InjectedChannel,
sConfigInjected->InjectedRank,
sConfigInjected->InjectedNbrOfConversion) );
}
else
{
/* Clear the old SQx bits for the selected rank */
MODIFY_REG(hadc->Instance->JSQR ,
ADC_JSQR_JL |
ADC_JSQR_RK_JL(ADC_JSQR_JSQ1,
sConfigInjected->InjectedRank,
sConfigInjected->InjectedNbrOfConversion) ,
0x00000000U);
}
}
/* Configuration of injected group */
/* Parameters update conditioned to ADC state: */
/* Parameters that can be updated only when ADC is disabled: */
/* - external trigger to start conversion */
/* Parameters update not conditioned to ADC state: */
/* - Automatic injected conversion */
/* - Injected discontinuous mode */
/* Note: In case of ADC already enabled, caution to not launch an unwanted */
/* conversion while modifying register CR2 by writing 1 to bit ADON. */
if (ADC_IS_ENABLE(hadc) == RESET)
{
MODIFY_REG(hadc->Instance->CR2 ,
ADC_CR2_JEXTSEL |
ADC_CR2_ADON ,
ADC_CFGR_JEXTSEL(hadc, sConfigInjected->ExternalTrigInjecConv) );
}
/* Configuration of injected group */
/* - Automatic injected conversion */
/* - Injected discontinuous mode */
/* Automatic injected conversion can be enabled if injected group */
/* external triggers are disabled. */
if (sConfigInjected->AutoInjectedConv == ENABLE)
{
if (sConfigInjected->ExternalTrigInjecConv == ADC_INJECTED_SOFTWARE_START)
{
SET_BIT(hadc->Instance->CR1, ADC_CR1_JAUTO);
}
else
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
tmp_hal_status = HAL_ERROR;
}
}
/* Injected discontinuous can be enabled only if auto-injected mode is */
/* disabled. */
if (sConfigInjected->InjectedDiscontinuousConvMode == ENABLE)
{
if (sConfigInjected->AutoInjectedConv == DISABLE)
{
SET_BIT(hadc->Instance->CR1, ADC_CR1_JDISCEN);
}
else
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
tmp_hal_status = HAL_ERROR;
}
}
/* InjectedChannel sampling time configuration */
/* For channels 10 to 17 */
if (sConfigInjected->InjectedChannel >= ADC_CHANNEL_10)
{
MODIFY_REG(hadc->Instance->SMPR1 ,
ADC_SMPR1(ADC_SMPR1_SMP10, sConfigInjected->InjectedChannel) ,
ADC_SMPR1(sConfigInjected->InjectedSamplingTime, sConfigInjected->InjectedChannel) );
}
else /* For channels 0 to 9 */
{
MODIFY_REG(hadc->Instance->SMPR2 ,
ADC_SMPR2(ADC_SMPR2_SMP0, sConfigInjected->InjectedChannel) ,
ADC_SMPR2(sConfigInjected->InjectedSamplingTime, sConfigInjected->InjectedChannel) );
}
/* If ADC1 InjectedChannel_16 or InjectedChannel_17 is selected, enable Temperature sensor */
/* and VREFINT measurement path. */
if ((sConfigInjected->InjectedChannel == ADC_CHANNEL_TEMPSENSOR) ||
(sConfigInjected->InjectedChannel == ADC_CHANNEL_VREFINT) )
{
SET_BIT(hadc->Instance->CR2, ADC_CR2_TSVREFE);
}
/* Configure the offset: offset enable/disable, InjectedChannel, offset value */
switch(sConfigInjected->InjectedRank)
{
case 1:
/* Set injected channel 1 offset */
MODIFY_REG(hadc->Instance->JOFR1,
ADC_JOFR1_JOFFSET1,
sConfigInjected->InjectedOffset);
break;
case 2:
/* Set injected channel 2 offset */
MODIFY_REG(hadc->Instance->JOFR2,
ADC_JOFR2_JOFFSET2,
sConfigInjected->InjectedOffset);
break;
case 3:
/* Set injected channel 3 offset */
MODIFY_REG(hadc->Instance->JOFR3,
ADC_JOFR3_JOFFSET3,
sConfigInjected->InjectedOffset);
break;
case 4:
default:
MODIFY_REG(hadc->Instance->JOFR4,
ADC_JOFR4_JOFFSET4,
sConfigInjected->InjectedOffset);
break;
}
/* If ADC1 Channel_16 or Channel_17 is selected, enable Temperature sensor */
/* and VREFINT measurement path. */
if ((sConfigInjected->InjectedChannel == ADC_CHANNEL_TEMPSENSOR) ||
(sConfigInjected->InjectedChannel == ADC_CHANNEL_VREFINT) )
{
/* For STM32F1 devices with several ADC: Only ADC1 can access internal */
/* measurement channels (VrefInt/TempSensor). If these channels are */
/* intended to be set on other ADC instances, an error is reported. */
if (hadc->Instance == ADC1)
{
if (READ_BIT(hadc->Instance->CR2, ADC_CR2_TSVREFE) == RESET)
{
SET_BIT(hadc->Instance->CR2, ADC_CR2_TSVREFE);
if ((sConfigInjected->InjectedChannel == ADC_CHANNEL_TEMPSENSOR))
{
/* Delay for temperature sensor stabilization time */
/* Compute number of CPU cycles to wait for */
wait_loop_index = (ADC_TEMPSENSOR_DELAY_US * (SystemCoreClock / 1000000U));
while(wait_loop_index != 0U)
{
wait_loop_index--;
}
}
}
}
else
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
tmp_hal_status = HAL_ERROR;
}
}
/* Process unlocked */
__HAL_UNLOCK(hadc);
/* Return function status */
return tmp_hal_status;
}
#if defined (STM32F103x6) || defined (STM32F103xB) || defined (STM32F105xC) || defined (STM32F107xC) || defined (STM32F103xE) || defined (STM32F103xG)
/**
* @brief Enable ADC multimode and configure multimode parameters
* @note Possibility to update parameters on the fly:
* This function initializes multimode parameters, following
* calls to this function can be used to reconfigure some parameters
* of structure "ADC_MultiModeTypeDef" on the fly, without resetting
* the ADCs (both ADCs of the common group).
* The setting of these parameters is conditioned to ADC state.
* For parameters constraints, see comments of structure
* "ADC_MultiModeTypeDef".
* @note To change back configuration from multimode to single mode, ADC must
* be reset (using function HAL_ADC_Init() ).
* @param hadc: ADC handle
* @param multimode: Structure of ADC multimode configuration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_ADCEx_MultiModeConfigChannel(ADC_HandleTypeDef* hadc, ADC_MultiModeTypeDef* multimode)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
ADC_HandleTypeDef tmphadcSlave={0};
/* Check the parameters */
assert_param(IS_ADC_MULTIMODE_MASTER_INSTANCE(hadc->Instance));
assert_param(IS_ADC_MODE(multimode->Mode));
/* Process locked */
__HAL_LOCK(hadc);
/* Set a temporary handle of the ADC slave associated to the ADC master */
ADC_MULTI_SLAVE(hadc, &tmphadcSlave);
/* Parameters update conditioned to ADC state: */
/* Parameters that can be updated when ADC is disabled or enabled without */
/* conversion on going on regular group: */
/* - ADC master and ADC slave DMA configuration */
/* Parameters that can be updated only when ADC is disabled: */
/* - Multimode mode selection */
/* To optimize code, all multimode settings can be set when both ADCs of */
/* the common group are in state: disabled. */
if ((ADC_IS_ENABLE(hadc) == RESET) &&
(ADC_IS_ENABLE(&tmphadcSlave) == RESET) &&
(IS_ADC_MULTIMODE_MASTER_INSTANCE(hadc->Instance)) )
{
MODIFY_REG(hadc->Instance->CR1,
ADC_CR1_DUALMOD ,
multimode->Mode );
}
/* If one of the ADC sharing the same common group is enabled, no update */
/* could be done on neither of the multimode structure parameters. */
else
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
tmp_hal_status = HAL_ERROR;
}
/* Process unlocked */
__HAL_UNLOCK(hadc);
/* Return function status */
return tmp_hal_status;
}
#endif /* defined STM32F103x6 || defined STM32F103xB || defined STM32F105xC || defined STM32F107xC || defined STM32F103xE || defined STM32F103xG */
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_ADC_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,529 @@
/**
******************************************************************************
* @file stm32f1xx_hal_cortex.c
* @author MCD Application Team
* @brief CORTEX HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the CORTEX:
* + Initialization and de-initialization functions
* + Peripheral Control functions
*
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
*** How to configure Interrupts using CORTEX HAL driver ***
===========================================================
[..]
This section provides functions allowing to configure the NVIC interrupts (IRQ).
The Cortex-M3 exceptions are managed by CMSIS functions.
(#) Configure the NVIC Priority Grouping using HAL_NVIC_SetPriorityGrouping()
function according to the following table.
(#) Configure the priority of the selected IRQ Channels using HAL_NVIC_SetPriority().
(#) Enable the selected IRQ Channels using HAL_NVIC_EnableIRQ().
(#) please refer to programming manual for details in how to configure priority.
-@- When the NVIC_PRIORITYGROUP_0 is selected, IRQ preemption is no more possible.
The pending IRQ priority will be managed only by the sub priority.
-@- IRQ priority order (sorted by highest to lowest priority):
(+@) Lowest preemption priority
(+@) Lowest sub priority
(+@) Lowest hardware priority (IRQ number)
[..]
*** How to configure Systick using CORTEX HAL driver ***
========================================================
[..]
Setup SysTick Timer for time base.
(+) The HAL_SYSTICK_Config()function calls the SysTick_Config() function which
is a CMSIS function that:
(++) Configures the SysTick Reload register with value passed as function parameter.
(++) Configures the SysTick IRQ priority to the lowest value 0x0F.
(++) Resets the SysTick Counter register.
(++) Configures the SysTick Counter clock source to be Core Clock Source (HCLK).
(++) Enables the SysTick Interrupt.
(++) Starts the SysTick Counter.
(+) You can change the SysTick Clock source to be HCLK_Div8 by calling the macro
__HAL_CORTEX_SYSTICKCLK_CONFIG(SYSTICK_CLKSOURCE_HCLK_DIV8) just after the
HAL_SYSTICK_Config() function call. The __HAL_CORTEX_SYSTICKCLK_CONFIG() macro is defined
inside the stm32f1xx_hal_cortex.h file.
(+) You can change the SysTick IRQ priority by calling the
HAL_NVIC_SetPriority(SysTick_IRQn,...) function just after the HAL_SYSTICK_Config() function
call. The HAL_NVIC_SetPriority() call the NVIC_SetPriority() function which is a CMSIS function.
(+) To adjust the SysTick time base, use the following formula:
Reload Value = SysTick Counter Clock (Hz) x Desired Time base (s)
(++) Reload Value is the parameter to be passed for HAL_SYSTICK_Config() function
(++) Reload Value should not exceed 0xFFFFFF
@endverbatim
******************************************************************************
* @attention
*
* Copyright (c) 2017 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file in
* the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup CORTEX CORTEX
* @brief CORTEX HAL module driver
* @{
*/
#ifdef HAL_CORTEX_MODULE_ENABLED
/* Private types -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private constants ---------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup CORTEX_Exported_Functions CORTEX Exported Functions
* @{
*/
/** @defgroup CORTEX_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
==============================================================================
##### Initialization and de-initialization functions #####
==============================================================================
[..]
This section provides the CORTEX HAL driver functions allowing to configure Interrupts
Systick functionalities
@endverbatim
* @{
*/
/**
* @brief Sets the priority grouping field (preemption priority and subpriority)
* using the required unlock sequence.
* @param PriorityGroup: The priority grouping bits length.
* This parameter can be one of the following values:
* @arg NVIC_PRIORITYGROUP_0: 0 bits for preemption priority
* 4 bits for subpriority
* @arg NVIC_PRIORITYGROUP_1: 1 bits for preemption priority
* 3 bits for subpriority
* @arg NVIC_PRIORITYGROUP_2: 2 bits for preemption priority
* 2 bits for subpriority
* @arg NVIC_PRIORITYGROUP_3: 3 bits for preemption priority
* 1 bits for subpriority
* @arg NVIC_PRIORITYGROUP_4: 4 bits for preemption priority
* 0 bits for subpriority
* @note When the NVIC_PriorityGroup_0 is selected, IRQ preemption is no more possible.
* The pending IRQ priority will be managed only by the subpriority.
* @retval None
*/
void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
{
/* Check the parameters */
assert_param(IS_NVIC_PRIORITY_GROUP(PriorityGroup));
/* Set the PRIGROUP[10:8] bits according to the PriorityGroup parameter value */
NVIC_SetPriorityGrouping(PriorityGroup);
}
/**
* @brief Sets the priority of an interrupt.
* @param IRQn: External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f10xx.h))
* @param PreemptPriority: The preemption priority for the IRQn channel.
* This parameter can be a value between 0 and 15
* A lower priority value indicates a higher priority
* @param SubPriority: the subpriority level for the IRQ channel.
* This parameter can be a value between 0 and 15
* A lower priority value indicates a higher priority.
* @retval None
*/
void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)
{
uint32_t prioritygroup = 0x00U;
/* Check the parameters */
assert_param(IS_NVIC_SUB_PRIORITY(SubPriority));
assert_param(IS_NVIC_PREEMPTION_PRIORITY(PreemptPriority));
prioritygroup = NVIC_GetPriorityGrouping();
NVIC_SetPriority(IRQn, NVIC_EncodePriority(prioritygroup, PreemptPriority, SubPriority));
}
/**
* @brief Enables a device specific interrupt in the NVIC interrupt controller.
* @note To configure interrupts priority correctly, the NVIC_PriorityGroupConfig()
* function should be called before.
* @param IRQn External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f10xxx.h))
* @retval None
*/
void HAL_NVIC_EnableIRQ(IRQn_Type IRQn)
{
/* Check the parameters */
assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
/* Enable interrupt */
NVIC_EnableIRQ(IRQn);
}
/**
* @brief Disables a device specific interrupt in the NVIC interrupt controller.
* @param IRQn External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f10xxx.h))
* @retval None
*/
void HAL_NVIC_DisableIRQ(IRQn_Type IRQn)
{
/* Check the parameters */
assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
/* Disable interrupt */
NVIC_DisableIRQ(IRQn);
}
/**
* @brief Initiates a system reset request to reset the MCU.
* @retval None
*/
void HAL_NVIC_SystemReset(void)
{
/* System Reset */
NVIC_SystemReset();
}
/**
* @brief Initializes the System Timer and its interrupt, and starts the System Tick Timer.
* Counter is in free running mode to generate periodic interrupts.
* @param TicksNumb: Specifies the ticks Number of ticks between two interrupts.
* @retval status: - 0 Function succeeded.
* - 1 Function failed.
*/
uint32_t HAL_SYSTICK_Config(uint32_t TicksNumb)
{
return SysTick_Config(TicksNumb);
}
/**
* @}
*/
/** @defgroup CORTEX_Exported_Functions_Group2 Peripheral Control functions
* @brief Cortex control functions
*
@verbatim
==============================================================================
##### Peripheral Control functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to control the CORTEX
(NVIC, SYSTICK, MPU) functionalities.
@endverbatim
* @{
*/
#if (__MPU_PRESENT == 1U)
/**
* @brief Disables the MPU
* @retval None
*/
void HAL_MPU_Disable(void)
{
/* Make sure outstanding transfers are done */
__DMB();
/* Disable fault exceptions */
SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;
/* Disable the MPU and clear the control register*/
MPU->CTRL = 0U;
}
/**
* @brief Enable the MPU.
* @param MPU_Control: Specifies the control mode of the MPU during hard fault,
* NMI, FAULTMASK and privileged access to the default memory
* This parameter can be one of the following values:
* @arg MPU_HFNMI_PRIVDEF_NONE
* @arg MPU_HARDFAULT_NMI
* @arg MPU_PRIVILEGED_DEFAULT
* @arg MPU_HFNMI_PRIVDEF
* @retval None
*/
void HAL_MPU_Enable(uint32_t MPU_Control)
{
/* Enable the MPU */
MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk;
/* Enable fault exceptions */
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
/* Ensure MPU setting take effects */
__DSB();
__ISB();
}
/**
* @brief Enable the MPU Region.
* @retval None
*/
void HAL_MPU_EnableRegion(uint32_t RegionNumber)
{
/* Check the parameters */
assert_param(IS_MPU_REGION_NUMBER(RegionNumber));
/* Set the Region number */
MPU->RNR = RegionNumber;
/* Enable the Region */
SET_BIT(MPU->RASR, MPU_RASR_ENABLE_Msk);
}
/**
* @brief Disable the MPU Region.
* @retval None
*/
void HAL_MPU_DisableRegion(uint32_t RegionNumber)
{
/* Check the parameters */
assert_param(IS_MPU_REGION_NUMBER(RegionNumber));
/* Set the Region number */
MPU->RNR = RegionNumber;
/* Disable the Region */
CLEAR_BIT(MPU->RASR, MPU_RASR_ENABLE_Msk);
}
/**
* @brief Initializes and configures the Region and the memory to be protected.
* @param MPU_Init: Pointer to a MPU_Region_InitTypeDef structure that contains
* the initialization and configuration information.
* @retval None
*/
void HAL_MPU_ConfigRegion(MPU_Region_InitTypeDef *MPU_Init)
{
/* Check the parameters */
assert_param(IS_MPU_REGION_NUMBER(MPU_Init->Number));
assert_param(IS_MPU_REGION_ENABLE(MPU_Init->Enable));
assert_param(IS_MPU_INSTRUCTION_ACCESS(MPU_Init->DisableExec));
assert_param(IS_MPU_REGION_PERMISSION_ATTRIBUTE(MPU_Init->AccessPermission));
assert_param(IS_MPU_TEX_LEVEL(MPU_Init->TypeExtField));
assert_param(IS_MPU_ACCESS_SHAREABLE(MPU_Init->IsShareable));
assert_param(IS_MPU_ACCESS_CACHEABLE(MPU_Init->IsCacheable));
assert_param(IS_MPU_ACCESS_BUFFERABLE(MPU_Init->IsBufferable));
assert_param(IS_MPU_SUB_REGION_DISABLE(MPU_Init->SubRegionDisable));
assert_param(IS_MPU_REGION_SIZE(MPU_Init->Size));
/* Set the Region number */
MPU->RNR = MPU_Init->Number;
/* Disable the Region */
CLEAR_BIT(MPU->RASR, MPU_RASR_ENABLE_Msk);
/* Apply configuration */
MPU->RBAR = MPU_Init->BaseAddress;
MPU->RASR = ((uint32_t)MPU_Init->DisableExec << MPU_RASR_XN_Pos) |
((uint32_t)MPU_Init->AccessPermission << MPU_RASR_AP_Pos) |
((uint32_t)MPU_Init->TypeExtField << MPU_RASR_TEX_Pos) |
((uint32_t)MPU_Init->IsShareable << MPU_RASR_S_Pos) |
((uint32_t)MPU_Init->IsCacheable << MPU_RASR_C_Pos) |
((uint32_t)MPU_Init->IsBufferable << MPU_RASR_B_Pos) |
((uint32_t)MPU_Init->SubRegionDisable << MPU_RASR_SRD_Pos) |
((uint32_t)MPU_Init->Size << MPU_RASR_SIZE_Pos) |
((uint32_t)MPU_Init->Enable << MPU_RASR_ENABLE_Pos);
}
#endif /* __MPU_PRESENT */
/**
* @brief Gets the priority grouping field from the NVIC Interrupt Controller.
* @retval Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field)
*/
uint32_t HAL_NVIC_GetPriorityGrouping(void)
{
/* Get the PRIGROUP[10:8] field value */
return NVIC_GetPriorityGrouping();
}
/**
* @brief Gets the priority of an interrupt.
* @param IRQn: External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f10xxx.h))
* @param PriorityGroup: the priority grouping bits length.
* This parameter can be one of the following values:
* @arg NVIC_PRIORITYGROUP_0: 0 bits for preemption priority
* 4 bits for subpriority
* @arg NVIC_PRIORITYGROUP_1: 1 bits for preemption priority
* 3 bits for subpriority
* @arg NVIC_PRIORITYGROUP_2: 2 bits for preemption priority
* 2 bits for subpriority
* @arg NVIC_PRIORITYGROUP_3: 3 bits for preemption priority
* 1 bits for subpriority
* @arg NVIC_PRIORITYGROUP_4: 4 bits for preemption priority
* 0 bits for subpriority
* @param pPreemptPriority: Pointer on the Preemptive priority value (starting from 0).
* @param pSubPriority: Pointer on the Subpriority value (starting from 0).
* @retval None
*/
void HAL_NVIC_GetPriority(IRQn_Type IRQn, uint32_t PriorityGroup, uint32_t *pPreemptPriority, uint32_t *pSubPriority)
{
/* Check the parameters */
assert_param(IS_NVIC_PRIORITY_GROUP(PriorityGroup));
/* Get priority for Cortex-M system or device specific interrupts */
NVIC_DecodePriority(NVIC_GetPriority(IRQn), PriorityGroup, pPreemptPriority, pSubPriority);
}
/**
* @brief Sets Pending bit of an external interrupt.
* @param IRQn External interrupt number
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f10xxx.h))
* @retval None
*/
void HAL_NVIC_SetPendingIRQ(IRQn_Type IRQn)
{
/* Check the parameters */
assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
/* Set interrupt pending */
NVIC_SetPendingIRQ(IRQn);
}
/**
* @brief Gets Pending Interrupt (reads the pending register in the NVIC
* and returns the pending bit for the specified interrupt).
* @param IRQn External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f10xxx.h))
* @retval status: - 0 Interrupt status is not pending.
* - 1 Interrupt status is pending.
*/
uint32_t HAL_NVIC_GetPendingIRQ(IRQn_Type IRQn)
{
/* Check the parameters */
assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
/* Return 1 if pending else 0 */
return NVIC_GetPendingIRQ(IRQn);
}
/**
* @brief Clears the pending bit of an external interrupt.
* @param IRQn External interrupt number.
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f10xxx.h))
* @retval None
*/
void HAL_NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{
/* Check the parameters */
assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
/* Clear pending interrupt */
NVIC_ClearPendingIRQ(IRQn);
}
/**
* @brief Gets active interrupt ( reads the active register in NVIC and returns the active bit).
* @param IRQn External interrupt number
* This parameter can be an enumerator of IRQn_Type enumeration
* (For the complete STM32 Devices IRQ Channels list, please refer to the appropriate CMSIS device file (stm32f10xxx.h))
* @retval status: - 0 Interrupt status is not pending.
* - 1 Interrupt status is pending.
*/
uint32_t HAL_NVIC_GetActive(IRQn_Type IRQn)
{
/* Check the parameters */
assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
/* Return 1 if active else 0 */
return NVIC_GetActive(IRQn);
}
/**
* @brief Configures the SysTick clock source.
* @param CLKSource: specifies the SysTick clock source.
* This parameter can be one of the following values:
* @arg SYSTICK_CLKSOURCE_HCLK_DIV8: AHB clock divided by 8 selected as SysTick clock source.
* @arg SYSTICK_CLKSOURCE_HCLK: AHB clock selected as SysTick clock source.
* @retval None
*/
void HAL_SYSTICK_CLKSourceConfig(uint32_t CLKSource)
{
/* Check the parameters */
assert_param(IS_SYSTICK_CLK_SOURCE(CLKSource));
if (CLKSource == SYSTICK_CLKSOURCE_HCLK)
{
SysTick->CTRL |= SYSTICK_CLKSOURCE_HCLK;
}
else
{
SysTick->CTRL &= ~SYSTICK_CLKSOURCE_HCLK;
}
}
/**
* @brief This function handles SYSTICK interrupt request.
* @retval None
*/
void HAL_SYSTICK_IRQHandler(void)
{
HAL_SYSTICK_Callback();
}
/**
* @brief SYSTICK callback.
* @retval None
*/
__weak void HAL_SYSTICK_Callback(void)
{
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_SYSTICK_Callback could be implemented in the user file
*/
}
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_CORTEX_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,897 @@
/**
******************************************************************************
* @file stm32f1xx_hal_dma.c
* @author MCD Application Team
* @brief DMA HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the Direct Memory Access (DMA) peripheral:
* + Initialization and de-initialization functions
* + IO operation functions
* + Peripheral State and errors functions
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
(#) Enable and configure the peripheral to be connected to the DMA Channel
(except for internal SRAM / FLASH memories: no initialization is
necessary). Please refer to the Reference manual for connection between peripherals
and DMA requests.
(#) For a given Channel, program the required configuration through the following parameters:
Channel request, Transfer Direction, Source and Destination data formats,
Circular or Normal mode, Channel Priority level, Source and Destination Increment mode
using HAL_DMA_Init() function.
(#) Use HAL_DMA_GetState() function to return the DMA state and HAL_DMA_GetError() in case of error
detection.
(#) Use HAL_DMA_Abort() function to abort the current transfer
-@- In Memory-to-Memory transfer mode, Circular mode is not allowed.
*** Polling mode IO operation ***
=================================
[..]
(+) Use HAL_DMA_Start() to start DMA transfer after the configuration of Source
address and destination address and the Length of data to be transferred
(+) Use HAL_DMA_PollForTransfer() to poll for the end of current transfer, in this
case a fixed Timeout can be configured by User depending from his application.
*** Interrupt mode IO operation ***
===================================
[..]
(+) Configure the DMA interrupt priority using HAL_NVIC_SetPriority()
(+) Enable the DMA IRQ handler using HAL_NVIC_EnableIRQ()
(+) Use HAL_DMA_Start_IT() to start DMA transfer after the configuration of
Source address and destination address and the Length of data to be transferred.
In this case the DMA interrupt is configured
(+) Use HAL_DMA_IRQHandler() called under DMA_IRQHandler() Interrupt subroutine
(+) At the end of data transfer HAL_DMA_IRQHandler() function is executed and user can
add his own function by customization of function pointer XferCpltCallback and
XferErrorCallback (i.e. a member of DMA handle structure).
*** DMA HAL driver macros list ***
=============================================
[..]
Below the list of most used macros in DMA HAL driver.
(+) __HAL_DMA_ENABLE: Enable the specified DMA Channel.
(+) __HAL_DMA_DISABLE: Disable the specified DMA Channel.
(+) __HAL_DMA_GET_FLAG: Get the DMA Channel pending flags.
(+) __HAL_DMA_CLEAR_FLAG: Clear the DMA Channel pending flags.
(+) __HAL_DMA_ENABLE_IT: Enable the specified DMA Channel interrupts.
(+) __HAL_DMA_DISABLE_IT: Disable the specified DMA Channel interrupts.
(+) __HAL_DMA_GET_IT_SOURCE: Check whether the specified DMA Channel interrupt has occurred or not.
[..]
(@) You can refer to the DMA HAL driver header file for more useful macros
@endverbatim
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file in
* the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup DMA DMA
* @brief DMA HAL module driver
* @{
*/
#ifdef HAL_DMA_MODULE_ENABLED
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup DMA_Private_Functions DMA Private Functions
* @{
*/
static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);
/**
* @}
*/
/* Exported functions ---------------------------------------------------------*/
/** @defgroup DMA_Exported_Functions DMA Exported Functions
* @{
*/
/** @defgroup DMA_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and de-initialization functions
*
@verbatim
===============================================================================
##### Initialization and de-initialization functions #####
===============================================================================
[..]
This section provides functions allowing to initialize the DMA Channel source
and destination addresses, incrementation and data sizes, transfer direction,
circular/normal mode selection, memory-to-memory mode selection and Channel priority value.
[..]
The HAL_DMA_Init() function follows the DMA configuration procedures as described in
reference manual.
@endverbatim
* @{
*/
/**
* @brief Initialize the DMA according to the specified
* parameters in the DMA_InitTypeDef and initialize the associated handle.
* @param hdma: Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma)
{
uint32_t tmp = 0U;
/* Check the DMA handle allocation */
if(hdma == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
assert_param(IS_DMA_DIRECTION(hdma->Init.Direction));
assert_param(IS_DMA_PERIPHERAL_INC_STATE(hdma->Init.PeriphInc));
assert_param(IS_DMA_MEMORY_INC_STATE(hdma->Init.MemInc));
assert_param(IS_DMA_PERIPHERAL_DATA_SIZE(hdma->Init.PeriphDataAlignment));
assert_param(IS_DMA_MEMORY_DATA_SIZE(hdma->Init.MemDataAlignment));
assert_param(IS_DMA_MODE(hdma->Init.Mode));
assert_param(IS_DMA_PRIORITY(hdma->Init.Priority));
#if defined (DMA2)
/* calculation of the channel index */
if ((uint32_t)(hdma->Instance) < (uint32_t)(DMA2_Channel1))
{
/* DMA1 */
hdma->ChannelIndex = (((uint32_t)hdma->Instance - (uint32_t)DMA1_Channel1) / ((uint32_t)DMA1_Channel2 - (uint32_t)DMA1_Channel1)) << 2;
hdma->DmaBaseAddress = DMA1;
}
else
{
/* DMA2 */
hdma->ChannelIndex = (((uint32_t)hdma->Instance - (uint32_t)DMA2_Channel1) / ((uint32_t)DMA2_Channel2 - (uint32_t)DMA2_Channel1)) << 2;
hdma->DmaBaseAddress = DMA2;
}
#else
/* DMA1 */
hdma->ChannelIndex = (((uint32_t)hdma->Instance - (uint32_t)DMA1_Channel1) / ((uint32_t)DMA1_Channel2 - (uint32_t)DMA1_Channel1)) << 2;
hdma->DmaBaseAddress = DMA1;
#endif /* DMA2 */
/* Change DMA peripheral state */
hdma->State = HAL_DMA_STATE_BUSY;
/* Get the CR register value */
tmp = hdma->Instance->CCR;
/* Clear PL, MSIZE, PSIZE, MINC, PINC, CIRC and DIR bits */
tmp &= ((uint32_t)~(DMA_CCR_PL | DMA_CCR_MSIZE | DMA_CCR_PSIZE | \
DMA_CCR_MINC | DMA_CCR_PINC | DMA_CCR_CIRC | \
DMA_CCR_DIR));
/* Prepare the DMA Channel configuration */
tmp |= hdma->Init.Direction |
hdma->Init.PeriphInc | hdma->Init.MemInc |
hdma->Init.PeriphDataAlignment | hdma->Init.MemDataAlignment |
hdma->Init.Mode | hdma->Init.Priority;
/* Write to DMA Channel CR register */
hdma->Instance->CCR = tmp;
/* Initialise the error code */
hdma->ErrorCode = HAL_DMA_ERROR_NONE;
/* Initialize the DMA state*/
hdma->State = HAL_DMA_STATE_READY;
/* Allocate lock resource and initialize it */
hdma->Lock = HAL_UNLOCKED;
return HAL_OK;
}
/**
* @brief DeInitialize the DMA peripheral.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_DeInit(DMA_HandleTypeDef *hdma)
{
/* Check the DMA handle allocation */
if(hdma == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
/* Disable the selected DMA Channelx */
__HAL_DMA_DISABLE(hdma);
/* Reset DMA Channel control register */
hdma->Instance->CCR = 0U;
/* Reset DMA Channel Number of Data to Transfer register */
hdma->Instance->CNDTR = 0U;
/* Reset DMA Channel peripheral address register */
hdma->Instance->CPAR = 0U;
/* Reset DMA Channel memory address register */
hdma->Instance->CMAR = 0U;
#if defined (DMA2)
/* calculation of the channel index */
if ((uint32_t)(hdma->Instance) < (uint32_t)(DMA2_Channel1))
{
/* DMA1 */
hdma->ChannelIndex = (((uint32_t)hdma->Instance - (uint32_t)DMA1_Channel1) / ((uint32_t)DMA1_Channel2 - (uint32_t)DMA1_Channel1)) << 2;
hdma->DmaBaseAddress = DMA1;
}
else
{
/* DMA2 */
hdma->ChannelIndex = (((uint32_t)hdma->Instance - (uint32_t)DMA2_Channel1) / ((uint32_t)DMA2_Channel2 - (uint32_t)DMA2_Channel1)) << 2;
hdma->DmaBaseAddress = DMA2;
}
#else
/* DMA1 */
hdma->ChannelIndex = (((uint32_t)hdma->Instance - (uint32_t)DMA1_Channel1) / ((uint32_t)DMA1_Channel2 - (uint32_t)DMA1_Channel1)) << 2;
hdma->DmaBaseAddress = DMA1;
#endif /* DMA2 */
/* Clear all flags */
hdma->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << (hdma->ChannelIndex));
/* Clean all callbacks */
hdma->XferCpltCallback = NULL;
hdma->XferHalfCpltCallback = NULL;
hdma->XferErrorCallback = NULL;
hdma->XferAbortCallback = NULL;
/* Reset the error code */
hdma->ErrorCode = HAL_DMA_ERROR_NONE;
/* Reset the DMA state */
hdma->State = HAL_DMA_STATE_RESET;
/* Release Lock */
__HAL_UNLOCK(hdma);
return HAL_OK;
}
/**
* @}
*/
/** @defgroup DMA_Exported_Functions_Group2 Input and Output operation functions
* @brief Input and Output operation functions
*
@verbatim
===============================================================================
##### IO operation functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Configure the source, destination address and data length and Start DMA transfer
(+) Configure the source, destination address and data length and
Start DMA transfer with interrupt
(+) Abort DMA transfer
(+) Poll for transfer complete
(+) Handle DMA interrupt request
@endverbatim
* @{
*/
/**
* @brief Start the DMA Transfer.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @param SrcAddress: The source memory Buffer address
* @param DstAddress: The destination memory Buffer address
* @param DataLength: The length of data to be transferred from source to destination
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
HAL_StatusTypeDef status = HAL_OK;
/* Check the parameters */
assert_param(IS_DMA_BUFFER_SIZE(DataLength));
/* Process locked */
__HAL_LOCK(hdma);
if(HAL_DMA_STATE_READY == hdma->State)
{
/* Change DMA peripheral state */
hdma->State = HAL_DMA_STATE_BUSY;
hdma->ErrorCode = HAL_DMA_ERROR_NONE;
/* Disable the peripheral */
__HAL_DMA_DISABLE(hdma);
/* Configure the source, destination address and the data length & clear flags*/
DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);
/* Enable the Peripheral */
__HAL_DMA_ENABLE(hdma);
}
else
{
/* Process Unlocked */
__HAL_UNLOCK(hdma);
status = HAL_BUSY;
}
return status;
}
/**
* @brief Start the DMA Transfer with interrupt enabled.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @param SrcAddress: The source memory Buffer address
* @param DstAddress: The destination memory Buffer address
* @param DataLength: The length of data to be transferred from source to destination
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
HAL_StatusTypeDef status = HAL_OK;
/* Check the parameters */
assert_param(IS_DMA_BUFFER_SIZE(DataLength));
/* Process locked */
__HAL_LOCK(hdma);
if(HAL_DMA_STATE_READY == hdma->State)
{
/* Change DMA peripheral state */
hdma->State = HAL_DMA_STATE_BUSY;
hdma->ErrorCode = HAL_DMA_ERROR_NONE;
/* Disable the peripheral */
__HAL_DMA_DISABLE(hdma);
/* Configure the source, destination address and the data length & clear flags*/
DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);
/* Enable the transfer complete interrupt */
/* Enable the transfer Error interrupt */
if(NULL != hdma->XferHalfCpltCallback)
{
/* Enable the Half transfer complete interrupt as well */
__HAL_DMA_ENABLE_IT(hdma, (DMA_IT_TC | DMA_IT_HT | DMA_IT_TE));
}
else
{
__HAL_DMA_DISABLE_IT(hdma, DMA_IT_HT);
__HAL_DMA_ENABLE_IT(hdma, (DMA_IT_TC | DMA_IT_TE));
}
/* Enable the Peripheral */
__HAL_DMA_ENABLE(hdma);
}
else
{
/* Process Unlocked */
__HAL_UNLOCK(hdma);
/* Remain BUSY */
status = HAL_BUSY;
}
return status;
}
/**
* @brief Abort the DMA Transfer.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *hdma)
{
HAL_StatusTypeDef status = HAL_OK;
if(hdma->State != HAL_DMA_STATE_BUSY)
{
/* no transfer ongoing */
hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
/* Process Unlocked */
__HAL_UNLOCK(hdma);
return HAL_ERROR;
}
else
{
/* Disable DMA IT */
__HAL_DMA_DISABLE_IT(hdma, (DMA_IT_TC | DMA_IT_HT | DMA_IT_TE));
/* Disable the channel */
__HAL_DMA_DISABLE(hdma);
/* Clear all flags */
hdma->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << hdma->ChannelIndex);
}
/* Change the DMA state */
hdma->State = HAL_DMA_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(hdma);
return status;
}
/**
* @brief Aborts the DMA Transfer in Interrupt mode.
* @param hdma : pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_Abort_IT(DMA_HandleTypeDef *hdma)
{
HAL_StatusTypeDef status = HAL_OK;
if(HAL_DMA_STATE_BUSY != hdma->State)
{
/* no transfer ongoing */
hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
status = HAL_ERROR;
}
else
{
/* Disable DMA IT */
__HAL_DMA_DISABLE_IT(hdma, (DMA_IT_TC | DMA_IT_HT | DMA_IT_TE));
/* Disable the channel */
__HAL_DMA_DISABLE(hdma);
/* Clear all flags */
__HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_GI_FLAG_INDEX(hdma));
/* Change the DMA state */
hdma->State = HAL_DMA_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(hdma);
/* Call User Abort callback */
if(hdma->XferAbortCallback != NULL)
{
hdma->XferAbortCallback(hdma);
}
}
return status;
}
/**
* @brief Polling for transfer complete.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @param CompleteLevel: Specifies the DMA level complete.
* @param Timeout: Timeout duration.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_PollForTransfer(DMA_HandleTypeDef *hdma, uint32_t CompleteLevel, uint32_t Timeout)
{
uint32_t temp;
uint32_t tickstart = 0U;
if(HAL_DMA_STATE_BUSY != hdma->State)
{
/* no transfer ongoing */
hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
__HAL_UNLOCK(hdma);
return HAL_ERROR;
}
/* Polling mode not supported in circular mode */
if (RESET != (hdma->Instance->CCR & DMA_CCR_CIRC))
{
hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED;
return HAL_ERROR;
}
/* Get the level transfer complete flag */
if(CompleteLevel == HAL_DMA_FULL_TRANSFER)
{
/* Transfer Complete flag */
temp = __HAL_DMA_GET_TC_FLAG_INDEX(hdma);
}
else
{
/* Half Transfer Complete flag */
temp = __HAL_DMA_GET_HT_FLAG_INDEX(hdma);
}
/* Get tick */
tickstart = HAL_GetTick();
while(__HAL_DMA_GET_FLAG(hdma, temp) == RESET)
{
if((__HAL_DMA_GET_FLAG(hdma, __HAL_DMA_GET_TE_FLAG_INDEX(hdma)) != RESET))
{
/* When a DMA transfer error occurs */
/* A hardware clear of its EN bits is performed */
/* Clear all flags */
hdma->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << hdma->ChannelIndex);
/* Update error code */
SET_BIT(hdma->ErrorCode, HAL_DMA_ERROR_TE);
/* Change the DMA state */
hdma->State= HAL_DMA_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(hdma);
return HAL_ERROR;
}
/* Check for the Timeout */
if(Timeout != HAL_MAX_DELAY)
{
if((Timeout == 0U) || ((HAL_GetTick() - tickstart) > Timeout))
{
/* Update error code */
SET_BIT(hdma->ErrorCode, HAL_DMA_ERROR_TIMEOUT);
/* Change the DMA state */
hdma->State = HAL_DMA_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(hdma);
return HAL_ERROR;
}
}
}
if(CompleteLevel == HAL_DMA_FULL_TRANSFER)
{
/* Clear the transfer complete flag */
__HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma));
/* The selected Channelx EN bit is cleared (DMA is disabled and
all transfers are complete) */
hdma->State = HAL_DMA_STATE_READY;
}
else
{
/* Clear the half transfer complete flag */
__HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma));
}
/* Process unlocked */
__HAL_UNLOCK(hdma);
return HAL_OK;
}
/**
* @brief Handles DMA interrupt request.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @retval None
*/
void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma)
{
uint32_t flag_it = hdma->DmaBaseAddress->ISR;
uint32_t source_it = hdma->Instance->CCR;
/* Half Transfer Complete Interrupt management ******************************/
if (((flag_it & (DMA_FLAG_HT1 << hdma->ChannelIndex)) != RESET) && ((source_it & DMA_IT_HT) != RESET))
{
/* Disable the half transfer interrupt if the DMA mode is not CIRCULAR */
if((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
{
/* Disable the half transfer interrupt */
__HAL_DMA_DISABLE_IT(hdma, DMA_IT_HT);
}
/* Clear the half transfer complete flag */
__HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma));
/* DMA peripheral state is not updated in Half Transfer */
/* but in Transfer Complete case */
if(hdma->XferHalfCpltCallback != NULL)
{
/* Half transfer callback */
hdma->XferHalfCpltCallback(hdma);
}
}
/* Transfer Complete Interrupt management ***********************************/
else if (((flag_it & (DMA_FLAG_TC1 << hdma->ChannelIndex)) != RESET) && ((source_it & DMA_IT_TC) != RESET))
{
if((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
{
/* Disable the transfer complete and error interrupt */
__HAL_DMA_DISABLE_IT(hdma, DMA_IT_TE | DMA_IT_TC);
/* Change the DMA state */
hdma->State = HAL_DMA_STATE_READY;
}
/* Clear the transfer complete flag */
__HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma));
/* Process Unlocked */
__HAL_UNLOCK(hdma);
if(hdma->XferCpltCallback != NULL)
{
/* Transfer complete callback */
hdma->XferCpltCallback(hdma);
}
}
/* Transfer Error Interrupt management **************************************/
else if (( RESET != (flag_it & (DMA_FLAG_TE1 << hdma->ChannelIndex))) && (RESET != (source_it & DMA_IT_TE)))
{
/* When a DMA transfer error occurs */
/* A hardware clear of its EN bits is performed */
/* Disable ALL DMA IT */
__HAL_DMA_DISABLE_IT(hdma, (DMA_IT_TC | DMA_IT_HT | DMA_IT_TE));
/* Clear all flags */
hdma->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << hdma->ChannelIndex);
/* Update error code */
hdma->ErrorCode = HAL_DMA_ERROR_TE;
/* Change the DMA state */
hdma->State = HAL_DMA_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(hdma);
if (hdma->XferErrorCallback != NULL)
{
/* Transfer error callback */
hdma->XferErrorCallback(hdma);
}
}
return;
}
/**
* @brief Register callbacks
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @param CallbackID: User Callback identifier
* a HAL_DMA_CallbackIDTypeDef ENUM as parameter.
* @param pCallback: pointer to private callback function which has pointer to
* a DMA_HandleTypeDef structure as parameter.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_RegisterCallback(DMA_HandleTypeDef *hdma, HAL_DMA_CallbackIDTypeDef CallbackID, void (* pCallback)( DMA_HandleTypeDef * _hdma))
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(hdma);
if(HAL_DMA_STATE_READY == hdma->State)
{
switch (CallbackID)
{
case HAL_DMA_XFER_CPLT_CB_ID:
hdma->XferCpltCallback = pCallback;
break;
case HAL_DMA_XFER_HALFCPLT_CB_ID:
hdma->XferHalfCpltCallback = pCallback;
break;
case HAL_DMA_XFER_ERROR_CB_ID:
hdma->XferErrorCallback = pCallback;
break;
case HAL_DMA_XFER_ABORT_CB_ID:
hdma->XferAbortCallback = pCallback;
break;
default:
status = HAL_ERROR;
break;
}
}
else
{
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hdma);
return status;
}
/**
* @brief UnRegister callbacks
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @param CallbackID: User Callback identifier
* a HAL_DMA_CallbackIDTypeDef ENUM as parameter.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_UnRegisterCallback(DMA_HandleTypeDef *hdma, HAL_DMA_CallbackIDTypeDef CallbackID)
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(hdma);
if(HAL_DMA_STATE_READY == hdma->State)
{
switch (CallbackID)
{
case HAL_DMA_XFER_CPLT_CB_ID:
hdma->XferCpltCallback = NULL;
break;
case HAL_DMA_XFER_HALFCPLT_CB_ID:
hdma->XferHalfCpltCallback = NULL;
break;
case HAL_DMA_XFER_ERROR_CB_ID:
hdma->XferErrorCallback = NULL;
break;
case HAL_DMA_XFER_ABORT_CB_ID:
hdma->XferAbortCallback = NULL;
break;
case HAL_DMA_XFER_ALL_CB_ID:
hdma->XferCpltCallback = NULL;
hdma->XferHalfCpltCallback = NULL;
hdma->XferErrorCallback = NULL;
hdma->XferAbortCallback = NULL;
break;
default:
status = HAL_ERROR;
break;
}
}
else
{
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(hdma);
return status;
}
/**
* @}
*/
/** @defgroup DMA_Exported_Functions_Group3 Peripheral State and Errors functions
* @brief Peripheral State and Errors functions
*
@verbatim
===============================================================================
##### Peripheral State and Errors functions #####
===============================================================================
[..]
This subsection provides functions allowing to
(+) Check the DMA state
(+) Get error code
@endverbatim
* @{
*/
/**
* @brief Return the DMA handle state.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @retval HAL state
*/
HAL_DMA_StateTypeDef HAL_DMA_GetState(DMA_HandleTypeDef *hdma)
{
/* Return DMA handle state */
return hdma->State;
}
/**
* @brief Return the DMA error code.
* @param hdma : pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @retval DMA Error Code
*/
uint32_t HAL_DMA_GetError(DMA_HandleTypeDef *hdma)
{
return hdma->ErrorCode;
}
/**
* @}
*/
/**
* @}
*/
/** @addtogroup DMA_Private_Functions
* @{
*/
/**
* @brief Sets the DMA Transfer parameter.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @param SrcAddress: The source memory Buffer address
* @param DstAddress: The destination memory Buffer address
* @param DataLength: The length of data to be transferred from source to destination
* @retval HAL status
*/
static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
/* Clear all flags */
hdma->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << hdma->ChannelIndex);
/* Configure DMA Channel data length */
hdma->Instance->CNDTR = DataLength;
/* Memory to Peripheral */
if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
{
/* Configure DMA Channel destination address */
hdma->Instance->CPAR = DstAddress;
/* Configure DMA Channel source address */
hdma->Instance->CMAR = SrcAddress;
}
/* Peripheral to Memory */
else
{
/* Configure DMA Channel source address */
hdma->Instance->CPAR = SrcAddress;
/* Configure DMA Channel destination address */
hdma->Instance->CMAR = DstAddress;
}
}
/**
* @}
*/
#endif /* HAL_DMA_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,553 @@
/**
******************************************************************************
* @file stm32f1xx_hal_exti.c
* @author MCD Application Team
* @brief EXTI HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the Extended Interrupts and events controller (EXTI) peripheral:
* + Initialization and de-initialization functions
* + IO operation functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2019 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### EXTI Peripheral features #####
==============================================================================
[..]
(+) Each Exti line can be configured within this driver.
(+) Exti line can be configured in 3 different modes
(++) Interrupt
(++) Event
(++) Both of them
(+) Configurable Exti lines can be configured with 3 different triggers
(++) Rising
(++) Falling
(++) Both of them
(+) When set in interrupt mode, configurable Exti lines have two different
interrupts pending registers which allow to distinguish which transition
occurs:
(++) Rising edge pending interrupt
(++) Falling
(+) Exti lines 0 to 15 are linked to gpio pin number 0 to 15. Gpio port can
be selected through multiplexer.
##### How to use this driver #####
==============================================================================
[..]
(#) Configure the EXTI line using HAL_EXTI_SetConfigLine().
(++) Choose the interrupt line number by setting "Line" member from
EXTI_ConfigTypeDef structure.
(++) Configure the interrupt and/or event mode using "Mode" member from
EXTI_ConfigTypeDef structure.
(++) For configurable lines, configure rising and/or falling trigger
"Trigger" member from EXTI_ConfigTypeDef structure.
(++) For Exti lines linked to gpio, choose gpio port using "GPIOSel"
member from GPIO_InitTypeDef structure.
(#) Get current Exti configuration of a dedicated line using
HAL_EXTI_GetConfigLine().
(++) Provide exiting handle as parameter.
(++) Provide pointer on EXTI_ConfigTypeDef structure as second parameter.
(#) Clear Exti configuration of a dedicated line using HAL_EXTI_ClearConfigLine().
(++) Provide exiting handle as parameter.
(#) Register callback to treat Exti interrupts using HAL_EXTI_RegisterCallback().
(++) Provide exiting handle as first parameter.
(++) Provide which callback will be registered using one value from
EXTI_CallbackIDTypeDef.
(++) Provide callback function pointer.
(#) Get interrupt pending bit using HAL_EXTI_GetPending().
(#) Clear interrupt pending bit using HAL_EXTI_ClearPending().
(#) Generate software interrupt using HAL_EXTI_GenerateSWI().
@endverbatim
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @addtogroup EXTI
* @{
*/
/** MISRA C:2012 deviation rule has been granted for following rule:
* Rule-18.1_b - Medium: Array `EXTICR' 1st subscript interval [0,7] may be out
* of bounds [0,3] in following API :
* HAL_EXTI_SetConfigLine
* HAL_EXTI_GetConfigLine
* HAL_EXTI_ClearConfigLine
*/
#ifdef HAL_EXTI_MODULE_ENABLED
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/** @defgroup EXTI_Private_Constants EXTI Private Constants
* @{
*/
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup EXTI_Exported_Functions
* @{
*/
/** @addtogroup EXTI_Exported_Functions_Group1
* @brief Configuration functions
*
@verbatim
===============================================================================
##### Configuration functions #####
===============================================================================
@endverbatim
* @{
*/
/**
* @brief Set configuration of a dedicated Exti line.
* @param hexti Exti handle.
* @param pExtiConfig Pointer on EXTI configuration to be set.
* @retval HAL Status.
*/
HAL_StatusTypeDef HAL_EXTI_SetConfigLine(EXTI_HandleTypeDef *hexti, EXTI_ConfigTypeDef *pExtiConfig)
{
uint32_t regval;
uint32_t linepos;
uint32_t maskline;
/* Check null pointer */
if ((hexti == NULL) || (pExtiConfig == NULL))
{
return HAL_ERROR;
}
/* Check parameters */
assert_param(IS_EXTI_LINE(pExtiConfig->Line));
assert_param(IS_EXTI_MODE(pExtiConfig->Mode));
/* Assign line number to handle */
hexti->Line = pExtiConfig->Line;
/* Compute line mask */
linepos = (pExtiConfig->Line & EXTI_PIN_MASK);
maskline = (1uL << linepos);
/* Configure triggers for configurable lines */
if ((pExtiConfig->Line & EXTI_CONFIG) != 0x00u)
{
assert_param(IS_EXTI_TRIGGER(pExtiConfig->Trigger));
/* Configure rising trigger */
/* Mask or set line */
if ((pExtiConfig->Trigger & EXTI_TRIGGER_RISING) != 0x00u)
{
EXTI->RTSR |= maskline;
}
else
{
EXTI->RTSR &= ~maskline;
}
/* Configure falling trigger */
/* Mask or set line */
if ((pExtiConfig->Trigger & EXTI_TRIGGER_FALLING) != 0x00u)
{
EXTI->FTSR |= maskline;
}
else
{
EXTI->FTSR &= ~maskline;
}
/* Configure gpio port selection in case of gpio exti line */
if ((pExtiConfig->Line & EXTI_GPIO) == EXTI_GPIO)
{
assert_param(IS_EXTI_GPIO_PORT(pExtiConfig->GPIOSel));
assert_param(IS_EXTI_GPIO_PIN(linepos));
regval = AFIO->EXTICR[linepos >> 2u];
regval &= ~(AFIO_EXTICR1_EXTI0 << (AFIO_EXTICR1_EXTI1_Pos * (linepos & 0x03u)));
regval |= (pExtiConfig->GPIOSel << (AFIO_EXTICR1_EXTI1_Pos * (linepos & 0x03u)));
AFIO->EXTICR[linepos >> 2u] = regval;
}
}
/* Configure interrupt mode : read current mode */
/* Mask or set line */
if ((pExtiConfig->Mode & EXTI_MODE_INTERRUPT) != 0x00u)
{
EXTI->IMR |= maskline;
}
else
{
EXTI->IMR &= ~maskline;
}
/* Configure event mode : read current mode */
/* Mask or set line */
if ((pExtiConfig->Mode & EXTI_MODE_EVENT) != 0x00u)
{
EXTI->EMR |= maskline;
}
else
{
EXTI->EMR &= ~maskline;
}
return HAL_OK;
}
/**
* @brief Get configuration of a dedicated Exti line.
* @param hexti Exti handle.
* @param pExtiConfig Pointer on structure to store Exti configuration.
* @retval HAL Status.
*/
HAL_StatusTypeDef HAL_EXTI_GetConfigLine(EXTI_HandleTypeDef *hexti, EXTI_ConfigTypeDef *pExtiConfig)
{
uint32_t regval;
uint32_t linepos;
uint32_t maskline;
/* Check null pointer */
if ((hexti == NULL) || (pExtiConfig == NULL))
{
return HAL_ERROR;
}
/* Check the parameter */
assert_param(IS_EXTI_LINE(hexti->Line));
/* Store handle line number to configuration structure */
pExtiConfig->Line = hexti->Line;
/* Compute line mask */
linepos = (pExtiConfig->Line & EXTI_PIN_MASK);
maskline = (1uL << linepos);
/* 1] Get core mode : interrupt */
/* Check if selected line is enable */
if ((EXTI->IMR & maskline) != 0x00u)
{
pExtiConfig->Mode = EXTI_MODE_INTERRUPT;
}
else
{
pExtiConfig->Mode = EXTI_MODE_NONE;
}
/* Get event mode */
/* Check if selected line is enable */
if ((EXTI->EMR & maskline) != 0x00u)
{
pExtiConfig->Mode |= EXTI_MODE_EVENT;
}
/* Get default Trigger and GPIOSel configuration */
pExtiConfig->Trigger = EXTI_TRIGGER_NONE;
pExtiConfig->GPIOSel = 0x00u;
/* 2] Get trigger for configurable lines : rising */
if ((pExtiConfig->Line & EXTI_CONFIG) != 0x00u)
{
/* Check if configuration of selected line is enable */
if ((EXTI->RTSR & maskline) != 0x00u)
{
pExtiConfig->Trigger = EXTI_TRIGGER_RISING;
}
/* Get falling configuration */
/* Check if configuration of selected line is enable */
if ((EXTI->FTSR & maskline) != 0x00u)
{
pExtiConfig->Trigger |= EXTI_TRIGGER_FALLING;
}
/* Get Gpio port selection for gpio lines */
if ((pExtiConfig->Line & EXTI_GPIO) == EXTI_GPIO)
{
assert_param(IS_EXTI_GPIO_PIN(linepos));
regval = AFIO->EXTICR[linepos >> 2u];
pExtiConfig->GPIOSel = (regval >> (AFIO_EXTICR1_EXTI1_Pos * (linepos & 0x03u))) & AFIO_EXTICR1_EXTI0;
}
}
return HAL_OK;
}
/**
* @brief Clear whole configuration of a dedicated Exti line.
* @param hexti Exti handle.
* @retval HAL Status.
*/
HAL_StatusTypeDef HAL_EXTI_ClearConfigLine(EXTI_HandleTypeDef *hexti)
{
uint32_t regval;
uint32_t linepos;
uint32_t maskline;
/* Check null pointer */
if (hexti == NULL)
{
return HAL_ERROR;
}
/* Check the parameter */
assert_param(IS_EXTI_LINE(hexti->Line));
/* compute line mask */
linepos = (hexti->Line & EXTI_PIN_MASK);
maskline = (1uL << linepos);
/* 1] Clear interrupt mode */
EXTI->IMR = (EXTI->IMR & ~maskline);
/* 2] Clear event mode */
EXTI->EMR = (EXTI->EMR & ~maskline);
/* 3] Clear triggers in case of configurable lines */
if ((hexti->Line & EXTI_CONFIG) != 0x00u)
{
EXTI->RTSR = (EXTI->RTSR & ~maskline);
EXTI->FTSR = (EXTI->FTSR & ~maskline);
/* Get Gpio port selection for gpio lines */
if ((hexti->Line & EXTI_GPIO) == EXTI_GPIO)
{
assert_param(IS_EXTI_GPIO_PIN(linepos));
regval = AFIO->EXTICR[linepos >> 2u];
regval &= ~(AFIO_EXTICR1_EXTI0 << (AFIO_EXTICR1_EXTI1_Pos * (linepos & 0x03u)));
AFIO->EXTICR[linepos >> 2u] = regval;
}
}
return HAL_OK;
}
/**
* @brief Register callback for a dedicated Exti line.
* @param hexti Exti handle.
* @param CallbackID User callback identifier.
* This parameter can be one of @arg @ref EXTI_CallbackIDTypeDef values.
* @param pPendingCbfn function pointer to be stored as callback.
* @retval HAL Status.
*/
HAL_StatusTypeDef HAL_EXTI_RegisterCallback(EXTI_HandleTypeDef *hexti, EXTI_CallbackIDTypeDef CallbackID, void (*pPendingCbfn)(void))
{
HAL_StatusTypeDef status = HAL_OK;
switch (CallbackID)
{
case HAL_EXTI_COMMON_CB_ID:
hexti->PendingCallback = pPendingCbfn;
break;
default:
status = HAL_ERROR;
break;
}
return status;
}
/**
* @brief Store line number as handle private field.
* @param hexti Exti handle.
* @param ExtiLine Exti line number.
* This parameter can be from 0 to @ref EXTI_LINE_NB.
* @retval HAL Status.
*/
HAL_StatusTypeDef HAL_EXTI_GetHandle(EXTI_HandleTypeDef *hexti, uint32_t ExtiLine)
{
/* Check the parameters */
assert_param(IS_EXTI_LINE(ExtiLine));
/* Check null pointer */
if (hexti == NULL)
{
return HAL_ERROR;
}
else
{
/* Store line number as handle private field */
hexti->Line = ExtiLine;
return HAL_OK;
}
}
/**
* @}
*/
/** @addtogroup EXTI_Exported_Functions_Group2
* @brief EXTI IO functions.
*
@verbatim
===============================================================================
##### IO operation functions #####
===============================================================================
@endverbatim
* @{
*/
/**
* @brief Handle EXTI interrupt request.
* @param hexti Exti handle.
* @retval none.
*/
void HAL_EXTI_IRQHandler(EXTI_HandleTypeDef *hexti)
{
uint32_t regval;
uint32_t maskline;
/* Compute line mask */
maskline = (1uL << (hexti->Line & EXTI_PIN_MASK));
/* Get pending bit */
regval = (EXTI->PR & maskline);
if (regval != 0x00u)
{
/* Clear pending bit */
EXTI->PR = maskline;
/* Call callback */
if (hexti->PendingCallback != NULL)
{
hexti->PendingCallback();
}
}
}
/**
* @brief Get interrupt pending bit of a dedicated line.
* @param hexti Exti handle.
* @param Edge Specify which pending edge as to be checked.
* This parameter can be one of the following values:
* @arg @ref EXTI_TRIGGER_RISING_FALLING
* This parameter is kept for compatibility with other series.
* @retval 1 if interrupt is pending else 0.
*/
uint32_t HAL_EXTI_GetPending(EXTI_HandleTypeDef *hexti, uint32_t Edge)
{
uint32_t regval;
uint32_t maskline;
uint32_t linepos;
/* Check parameters */
assert_param(IS_EXTI_LINE(hexti->Line));
assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
assert_param(IS_EXTI_PENDING_EDGE(Edge));
/* Prevent unused argument compilation warning */
UNUSED(Edge);
/* Compute line mask */
linepos = (hexti->Line & EXTI_PIN_MASK);
maskline = (1uL << linepos);
/* return 1 if bit is set else 0 */
regval = ((EXTI->PR & maskline) >> linepos);
return regval;
}
/**
* @brief Clear interrupt pending bit of a dedicated line.
* @param hexti Exti handle.
* @param Edge Specify which pending edge as to be clear.
* This parameter can be one of the following values:
* @arg @ref EXTI_TRIGGER_RISING_FALLING
* This parameter is kept for compatibility with other series.
* @retval None.
*/
void HAL_EXTI_ClearPending(EXTI_HandleTypeDef *hexti, uint32_t Edge)
{
uint32_t maskline;
/* Check parameters */
assert_param(IS_EXTI_LINE(hexti->Line));
assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
assert_param(IS_EXTI_PENDING_EDGE(Edge));
/* Prevent unused argument compilation warning */
UNUSED(Edge);
/* Compute line mask */
maskline = (1uL << (hexti->Line & EXTI_PIN_MASK));
/* Clear Pending bit */
EXTI->PR = maskline;
}
/**
* @brief Generate a software interrupt for a dedicated line.
* @param hexti Exti handle.
* @retval None.
*/
void HAL_EXTI_GenerateSWI(EXTI_HandleTypeDef *hexti)
{
uint32_t maskline;
/* Check parameters */
assert_param(IS_EXTI_LINE(hexti->Line));
assert_param(IS_EXTI_CONFIG_LINE(hexti->Line));
/* Compute line mask */
maskline = (1uL << (hexti->Line & EXTI_PIN_MASK));
/* Generate Software interrupt */
EXTI->SWIER = maskline;
}
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_EXTI_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,959 @@
/**
******************************************************************************
* @file stm32f1xx_hal_flash.c
* @author MCD Application Team
* @brief FLASH HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the internal FLASH memory:
* + Program operations functions
* + Memory Control functions
* + Peripheral State functions
*
@verbatim
==============================================================================
##### FLASH peripheral features #####
==============================================================================
[..] The Flash memory interface manages CPU AHB I-Code and D-Code accesses
to the Flash memory. It implements the erase and program Flash memory operations
and the read and write protection mechanisms.
[..] The Flash memory interface accelerates code execution with a system of instruction
prefetch.
[..] The FLASH main features are:
(+) Flash memory read operations
(+) Flash memory program/erase operations
(+) Read / write protections
(+) Prefetch on I-Code
(+) Option Bytes programming
##### How to use this driver #####
==============================================================================
[..]
This driver provides functions and macros to configure and program the FLASH
memory of all STM32F1xx devices.
(#) FLASH Memory I/O Programming functions: this group includes all needed
functions to erase and program the main memory:
(++) Lock and Unlock the FLASH interface
(++) Erase function: Erase page, erase all pages
(++) Program functions: half word, word and doubleword
(#) FLASH Option Bytes Programming functions: this group includes all needed
functions to manage the Option Bytes:
(++) Lock and Unlock the Option Bytes
(++) Set/Reset the write protection
(++) Set the Read protection Level
(++) Program the user Option Bytes
(++) Launch the Option Bytes loader
(++) Erase Option Bytes
(++) Program the data Option Bytes
(++) Get the Write protection.
(++) Get the user option bytes.
(#) Interrupts and flags management functions : this group
includes all needed functions to:
(++) Handle FLASH interrupts
(++) Wait for last FLASH operation according to its status
(++) Get error flag status
[..] In addition to these function, this driver includes a set of macros allowing
to handle the following operations:
(+) Set/Get the latency
(+) Enable/Disable the prefetch buffer
(+) Enable/Disable the half cycle access
(+) Enable/Disable the FLASH interrupts
(+) Monitor the FLASH flags status
@endverbatim
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file in
* the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
#ifdef HAL_FLASH_MODULE_ENABLED
/** @defgroup FLASH FLASH
* @brief FLASH HAL module driver
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup FLASH_Private_Constants FLASH Private Constants
* @{
*/
/**
* @}
*/
/* Private macro ---------------------------- ---------------------------------*/
/** @defgroup FLASH_Private_Macros FLASH Private Macros
* @{
*/
/**
* @}
*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup FLASH_Private_Variables FLASH Private Variables
* @{
*/
/* Variables used for Erase pages under interruption*/
FLASH_ProcessTypeDef pFlash;
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup FLASH_Private_Functions FLASH Private Functions
* @{
*/
static void FLASH_Program_HalfWord(uint32_t Address, uint16_t Data);
static void FLASH_SetErrorCode(void);
extern void FLASH_PageErase(uint32_t PageAddress);
/**
* @}
*/
/* Exported functions ---------------------------------------------------------*/
/** @defgroup FLASH_Exported_Functions FLASH Exported Functions
* @{
*/
/** @defgroup FLASH_Exported_Functions_Group1 Programming operation functions
* @brief Programming operation functions
*
@verbatim
@endverbatim
* @{
*/
/**
* @brief Program halfword, word or double word at a specified address
* @note The function HAL_FLASH_Unlock() should be called before to unlock the FLASH interface
* The function HAL_FLASH_Lock() should be called after to lock the FLASH interface
*
* @note If an erase and a program operations are requested simultaneously,
* the erase operation is performed before the program one.
*
* @note FLASH should be previously erased before new programmation (only exception to this
* is when 0x0000 is programmed)
*
* @param TypeProgram: Indicate the way to program at a specified address.
* This parameter can be a value of @ref FLASH_Type_Program
* @param Address: Specifies the address to be programmed.
* @param Data: Specifies the data to be programmed
*
* @retval HAL_StatusTypeDef HAL Status
*/
HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
{
HAL_StatusTypeDef status = HAL_ERROR;
uint8_t index = 0;
uint8_t nbiterations = 0;
/* Process Locked */
__HAL_LOCK(&pFlash);
/* Check the parameters */
assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));
assert_param(IS_FLASH_PROGRAM_ADDRESS(Address));
#if defined(FLASH_BANK2_END)
if(Address <= FLASH_BANK1_END)
{
#endif /* FLASH_BANK2_END */
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
#if defined(FLASH_BANK2_END)
}
else
{
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperationBank2(FLASH_TIMEOUT_VALUE);
}
#endif /* FLASH_BANK2_END */
if(status == HAL_OK)
{
if(TypeProgram == FLASH_TYPEPROGRAM_HALFWORD)
{
/* Program halfword (16-bit) at a specified address. */
nbiterations = 1U;
}
else if(TypeProgram == FLASH_TYPEPROGRAM_WORD)
{
/* Program word (32-bit = 2*16-bit) at a specified address. */
nbiterations = 2U;
}
else
{
/* Program double word (64-bit = 4*16-bit) at a specified address. */
nbiterations = 4U;
}
for (index = 0U; index < nbiterations; index++)
{
FLASH_Program_HalfWord((Address + (2U*index)), (uint16_t)(Data >> (16U*index)));
#if defined(FLASH_BANK2_END)
if(Address <= FLASH_BANK1_END)
{
#endif /* FLASH_BANK2_END */
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
/* If the program operation is completed, disable the PG Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_PG);
#if defined(FLASH_BANK2_END)
}
else
{
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperationBank2(FLASH_TIMEOUT_VALUE);
/* If the program operation is completed, disable the PG Bit */
CLEAR_BIT(FLASH->CR2, FLASH_CR2_PG);
}
#endif /* FLASH_BANK2_END */
/* In case of error, stop programation procedure */
if (status != HAL_OK)
{
break;
}
}
}
/* Process Unlocked */
__HAL_UNLOCK(&pFlash);
return status;
}
/**
* @brief Program halfword, word or double word at a specified address with interrupt enabled.
* @note The function HAL_FLASH_Unlock() should be called before to unlock the FLASH interface
* The function HAL_FLASH_Lock() should be called after to lock the FLASH interface
*
* @note If an erase and a program operations are requested simultaneously,
* the erase operation is performed before the program one.
*
* @param TypeProgram: Indicate the way to program at a specified address.
* This parameter can be a value of @ref FLASH_Type_Program
* @param Address: Specifies the address to be programmed.
* @param Data: Specifies the data to be programmed
*
* @retval HAL_StatusTypeDef HAL Status
*/
HAL_StatusTypeDef HAL_FLASH_Program_IT(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
{
HAL_StatusTypeDef status = HAL_OK;
/* Check the parameters */
assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));
assert_param(IS_FLASH_PROGRAM_ADDRESS(Address));
#if defined(FLASH_BANK2_END)
/* If procedure already ongoing, reject the next one */
if (pFlash.ProcedureOnGoing != FLASH_PROC_NONE)
{
return HAL_ERROR;
}
if(Address <= FLASH_BANK1_END)
{
/* Enable End of FLASH Operation and Error source interrupts */
__HAL_FLASH_ENABLE_IT(FLASH_IT_EOP_BANK1 | FLASH_IT_ERR_BANK1);
}else
{
/* Enable End of FLASH Operation and Error source interrupts */
__HAL_FLASH_ENABLE_IT(FLASH_IT_EOP_BANK2 | FLASH_IT_ERR_BANK2);
}
#else
/* Enable End of FLASH Operation and Error source interrupts */
__HAL_FLASH_ENABLE_IT(FLASH_IT_EOP | FLASH_IT_ERR);
#endif /* FLASH_BANK2_END */
pFlash.Address = Address;
pFlash.Data = Data;
if(TypeProgram == FLASH_TYPEPROGRAM_HALFWORD)
{
pFlash.ProcedureOnGoing = FLASH_PROC_PROGRAMHALFWORD;
/* Program halfword (16-bit) at a specified address. */
pFlash.DataRemaining = 1U;
}
else if(TypeProgram == FLASH_TYPEPROGRAM_WORD)
{
pFlash.ProcedureOnGoing = FLASH_PROC_PROGRAMWORD;
/* Program word (32-bit : 2*16-bit) at a specified address. */
pFlash.DataRemaining = 2U;
}
else
{
pFlash.ProcedureOnGoing = FLASH_PROC_PROGRAMDOUBLEWORD;
/* Program double word (64-bit : 4*16-bit) at a specified address. */
pFlash.DataRemaining = 4U;
}
/* Program halfword (16-bit) at a specified address. */
FLASH_Program_HalfWord(Address, (uint16_t)Data);
return status;
}
/**
* @brief This function handles FLASH interrupt request.
* @retval None
*/
void HAL_FLASH_IRQHandler(void)
{
uint32_t addresstmp = 0U;
/* Check FLASH operation error flags */
#if defined(FLASH_BANK2_END)
if(__HAL_FLASH_GET_FLAG(FLASH_FLAG_WRPERR_BANK1) || __HAL_FLASH_GET_FLAG(FLASH_FLAG_PGERR_BANK1) || \
(__HAL_FLASH_GET_FLAG(FLASH_FLAG_WRPERR_BANK2) || __HAL_FLASH_GET_FLAG(FLASH_FLAG_PGERR_BANK2)))
#else
if(__HAL_FLASH_GET_FLAG(FLASH_FLAG_WRPERR) ||__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGERR))
#endif /* FLASH_BANK2_END */
{
/* Return the faulty address */
addresstmp = pFlash.Address;
/* Reset address */
pFlash.Address = 0xFFFFFFFFU;
/* Save the Error code */
FLASH_SetErrorCode();
/* FLASH error interrupt user callback */
HAL_FLASH_OperationErrorCallback(addresstmp);
/* Stop the procedure ongoing */
pFlash.ProcedureOnGoing = FLASH_PROC_NONE;
}
/* Check FLASH End of Operation flag */
#if defined(FLASH_BANK2_END)
if(__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP_BANK1))
{
/* Clear FLASH End of Operation pending bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP_BANK1);
#else
if(__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP))
{
/* Clear FLASH End of Operation pending bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
#endif /* FLASH_BANK2_END */
/* Process can continue only if no error detected */
if(pFlash.ProcedureOnGoing != FLASH_PROC_NONE)
{
if(pFlash.ProcedureOnGoing == FLASH_PROC_PAGEERASE)
{
/* Nb of pages to erased can be decreased */
pFlash.DataRemaining--;
/* Check if there are still pages to erase */
if(pFlash.DataRemaining != 0U)
{
addresstmp = pFlash.Address;
/*Indicate user which sector has been erased */
HAL_FLASH_EndOfOperationCallback(addresstmp);
/*Increment sector number*/
addresstmp = pFlash.Address + FLASH_PAGE_SIZE;
pFlash.Address = addresstmp;
/* If the erase operation is completed, disable the PER Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_PER);
FLASH_PageErase(addresstmp);
}
else
{
/* No more pages to Erase, user callback can be called. */
/* Reset Sector and stop Erase pages procedure */
pFlash.Address = addresstmp = 0xFFFFFFFFU;
pFlash.ProcedureOnGoing = FLASH_PROC_NONE;
/* FLASH EOP interrupt user callback */
HAL_FLASH_EndOfOperationCallback(addresstmp);
}
}
else if(pFlash.ProcedureOnGoing == FLASH_PROC_MASSERASE)
{
/* Operation is completed, disable the MER Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_MER);
#if defined(FLASH_BANK2_END)
/* Stop Mass Erase procedure if no pending mass erase on other bank */
if (HAL_IS_BIT_CLR(FLASH->CR2, FLASH_CR2_MER))
{
#endif /* FLASH_BANK2_END */
/* MassErase ended. Return the selected bank */
/* FLASH EOP interrupt user callback */
HAL_FLASH_EndOfOperationCallback(0U);
/* Stop Mass Erase procedure*/
pFlash.ProcedureOnGoing = FLASH_PROC_NONE;
}
#if defined(FLASH_BANK2_END)
}
#endif /* FLASH_BANK2_END */
else
{
/* Nb of 16-bit data to program can be decreased */
pFlash.DataRemaining--;
/* Check if there are still 16-bit data to program */
if(pFlash.DataRemaining != 0U)
{
/* Increment address to 16-bit */
pFlash.Address += 2U;
addresstmp = pFlash.Address;
/* Shift to have next 16-bit data */
pFlash.Data = (pFlash.Data >> 16U);
/* Operation is completed, disable the PG Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_PG);
/*Program halfword (16-bit) at a specified address.*/
FLASH_Program_HalfWord(addresstmp, (uint16_t)pFlash.Data);
}
else
{
/* Program ended. Return the selected address */
/* FLASH EOP interrupt user callback */
if (pFlash.ProcedureOnGoing == FLASH_PROC_PROGRAMHALFWORD)
{
HAL_FLASH_EndOfOperationCallback(pFlash.Address);
}
else if (pFlash.ProcedureOnGoing == FLASH_PROC_PROGRAMWORD)
{
HAL_FLASH_EndOfOperationCallback(pFlash.Address - 2U);
}
else
{
HAL_FLASH_EndOfOperationCallback(pFlash.Address - 6U);
}
/* Reset Address and stop Program procedure */
pFlash.Address = 0xFFFFFFFFU;
pFlash.ProcedureOnGoing = FLASH_PROC_NONE;
}
}
}
}
#if defined(FLASH_BANK2_END)
/* Check FLASH End of Operation flag */
if(__HAL_FLASH_GET_FLAG( FLASH_FLAG_EOP_BANK2))
{
/* Clear FLASH End of Operation pending bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP_BANK2);
/* Process can continue only if no error detected */
if(pFlash.ProcedureOnGoing != FLASH_PROC_NONE)
{
if(pFlash.ProcedureOnGoing == FLASH_PROC_PAGEERASE)
{
/* Nb of pages to erased can be decreased */
pFlash.DataRemaining--;
/* Check if there are still pages to erase*/
if(pFlash.DataRemaining != 0U)
{
/* Indicate user which page address has been erased*/
HAL_FLASH_EndOfOperationCallback(pFlash.Address);
/* Increment page address to next page */
pFlash.Address += FLASH_PAGE_SIZE;
addresstmp = pFlash.Address;
/* Operation is completed, disable the PER Bit */
CLEAR_BIT(FLASH->CR2, FLASH_CR2_PER);
FLASH_PageErase(addresstmp);
}
else
{
/*No more pages to Erase*/
/*Reset Address and stop Erase pages procedure*/
pFlash.Address = 0xFFFFFFFFU;
pFlash.ProcedureOnGoing = FLASH_PROC_NONE;
/* FLASH EOP interrupt user callback */
HAL_FLASH_EndOfOperationCallback(pFlash.Address);
}
}
else if(pFlash.ProcedureOnGoing == FLASH_PROC_MASSERASE)
{
/* Operation is completed, disable the MER Bit */
CLEAR_BIT(FLASH->CR2, FLASH_CR2_MER);
if (HAL_IS_BIT_CLR(FLASH->CR, FLASH_CR_MER))
{
/* MassErase ended. Return the selected bank*/
/* FLASH EOP interrupt user callback */
HAL_FLASH_EndOfOperationCallback(0U);
pFlash.ProcedureOnGoing = FLASH_PROC_NONE;
}
}
else
{
/* Nb of 16-bit data to program can be decreased */
pFlash.DataRemaining--;
/* Check if there are still 16-bit data to program */
if(pFlash.DataRemaining != 0U)
{
/* Increment address to 16-bit */
pFlash.Address += 2U;
addresstmp = pFlash.Address;
/* Shift to have next 16-bit data */
pFlash.Data = (pFlash.Data >> 16U);
/* Operation is completed, disable the PG Bit */
CLEAR_BIT(FLASH->CR2, FLASH_CR2_PG);
/*Program halfword (16-bit) at a specified address.*/
FLASH_Program_HalfWord(addresstmp, (uint16_t)pFlash.Data);
}
else
{
/*Program ended. Return the selected address*/
/* FLASH EOP interrupt user callback */
if (pFlash.ProcedureOnGoing == FLASH_PROC_PROGRAMHALFWORD)
{
HAL_FLASH_EndOfOperationCallback(pFlash.Address);
}
else if (pFlash.ProcedureOnGoing == FLASH_PROC_PROGRAMWORD)
{
HAL_FLASH_EndOfOperationCallback(pFlash.Address-2U);
}
else
{
HAL_FLASH_EndOfOperationCallback(pFlash.Address-6U);
}
/* Reset Address and stop Program procedure*/
pFlash.Address = 0xFFFFFFFFU;
pFlash.ProcedureOnGoing = FLASH_PROC_NONE;
}
}
}
}
#endif
if(pFlash.ProcedureOnGoing == FLASH_PROC_NONE)
{
#if defined(FLASH_BANK2_END)
/* Operation is completed, disable the PG, PER and MER Bits for both bank */
CLEAR_BIT(FLASH->CR, (FLASH_CR_PG | FLASH_CR_PER | FLASH_CR_MER));
CLEAR_BIT(FLASH->CR2, (FLASH_CR2_PG | FLASH_CR2_PER | FLASH_CR2_MER));
/* Disable End of FLASH Operation and Error source interrupts for both banks */
__HAL_FLASH_DISABLE_IT(FLASH_IT_EOP_BANK1 | FLASH_IT_ERR_BANK1 | FLASH_IT_EOP_BANK2 | FLASH_IT_ERR_BANK2);
#else
/* Operation is completed, disable the PG, PER and MER Bits */
CLEAR_BIT(FLASH->CR, (FLASH_CR_PG | FLASH_CR_PER | FLASH_CR_MER));
/* Disable End of FLASH Operation and Error source interrupts */
__HAL_FLASH_DISABLE_IT(FLASH_IT_EOP | FLASH_IT_ERR);
#endif /* FLASH_BANK2_END */
}
}
/**
* @brief FLASH end of operation interrupt callback
* @param ReturnValue: The value saved in this parameter depends on the ongoing procedure
* - Mass Erase: No return value expected
* - Pages Erase: Address of the page which has been erased
* (if 0xFFFFFFFF, it means that all the selected pages have been erased)
* - Program: Address which was selected for data program
* @retval none
*/
__weak void HAL_FLASH_EndOfOperationCallback(uint32_t ReturnValue)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(ReturnValue);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_FLASH_EndOfOperationCallback could be implemented in the user file
*/
}
/**
* @brief FLASH operation error interrupt callback
* @param ReturnValue: The value saved in this parameter depends on the ongoing procedure
* - Mass Erase: No return value expected
* - Pages Erase: Address of the page which returned an error
* - Program: Address which was selected for data program
* @retval none
*/
__weak void HAL_FLASH_OperationErrorCallback(uint32_t ReturnValue)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(ReturnValue);
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_FLASH_OperationErrorCallback could be implemented in the user file
*/
}
/**
* @}
*/
/** @defgroup FLASH_Exported_Functions_Group2 Peripheral Control functions
* @brief management functions
*
@verbatim
===============================================================================
##### Peripheral Control functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to control the FLASH
memory operations.
@endverbatim
* @{
*/
/**
* @brief Unlock the FLASH control register access
* @retval HAL Status
*/
HAL_StatusTypeDef HAL_FLASH_Unlock(void)
{
HAL_StatusTypeDef status = HAL_OK;
if(READ_BIT(FLASH->CR, FLASH_CR_LOCK) != RESET)
{
/* Authorize the FLASH Registers access */
WRITE_REG(FLASH->KEYR, FLASH_KEY1);
WRITE_REG(FLASH->KEYR, FLASH_KEY2);
/* Verify Flash is unlocked */
if(READ_BIT(FLASH->CR, FLASH_CR_LOCK) != RESET)
{
status = HAL_ERROR;
}
}
#if defined(FLASH_BANK2_END)
if(READ_BIT(FLASH->CR2, FLASH_CR2_LOCK) != RESET)
{
/* Authorize the FLASH BANK2 Registers access */
WRITE_REG(FLASH->KEYR2, FLASH_KEY1);
WRITE_REG(FLASH->KEYR2, FLASH_KEY2);
/* Verify Flash BANK2 is unlocked */
if(READ_BIT(FLASH->CR2, FLASH_CR2_LOCK) != RESET)
{
status = HAL_ERROR;
}
}
#endif /* FLASH_BANK2_END */
return status;
}
/**
* @brief Locks the FLASH control register access
* @retval HAL Status
*/
HAL_StatusTypeDef HAL_FLASH_Lock(void)
{
/* Set the LOCK Bit to lock the FLASH Registers access */
SET_BIT(FLASH->CR, FLASH_CR_LOCK);
#if defined(FLASH_BANK2_END)
/* Set the LOCK Bit to lock the FLASH BANK2 Registers access */
SET_BIT(FLASH->CR2, FLASH_CR2_LOCK);
#endif /* FLASH_BANK2_END */
return HAL_OK;
}
/**
* @brief Unlock the FLASH Option Control Registers access.
* @retval HAL Status
*/
HAL_StatusTypeDef HAL_FLASH_OB_Unlock(void)
{
if (HAL_IS_BIT_CLR(FLASH->CR, FLASH_CR_OPTWRE))
{
/* Authorizes the Option Byte register programming */
WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY1);
WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY2);
}
else
{
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Lock the FLASH Option Control Registers access.
* @retval HAL Status
*/
HAL_StatusTypeDef HAL_FLASH_OB_Lock(void)
{
/* Clear the OPTWRE Bit to lock the FLASH Option Byte Registers access */
CLEAR_BIT(FLASH->CR, FLASH_CR_OPTWRE);
return HAL_OK;
}
/**
* @brief Launch the option byte loading.
* @note This function will reset automatically the MCU.
* @retval None
*/
void HAL_FLASH_OB_Launch(void)
{
/* Initiates a system reset request to launch the option byte loading */
HAL_NVIC_SystemReset();
}
/**
* @}
*/
/** @defgroup FLASH_Exported_Functions_Group3 Peripheral errors functions
* @brief Peripheral errors functions
*
@verbatim
===============================================================================
##### Peripheral Errors functions #####
===============================================================================
[..]
This subsection permit to get in run-time errors of the FLASH peripheral.
@endverbatim
* @{
*/
/**
* @brief Get the specific FLASH error flag.
* @retval FLASH_ErrorCode The returned value can be:
* @ref FLASH_Error_Codes
*/
uint32_t HAL_FLASH_GetError(void)
{
return pFlash.ErrorCode;
}
/**
* @}
*/
/**
* @}
*/
/** @addtogroup FLASH_Private_Functions
* @{
*/
/**
* @brief Program a half-word (16-bit) at a specified address.
* @param Address specify the address to be programmed.
* @param Data specify the data to be programmed.
* @retval None
*/
static void FLASH_Program_HalfWord(uint32_t Address, uint16_t Data)
{
/* Clean the error context */
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
#if defined(FLASH_BANK2_END)
if(Address <= FLASH_BANK1_END)
{
#endif /* FLASH_BANK2_END */
/* Proceed to program the new data */
SET_BIT(FLASH->CR, FLASH_CR_PG);
#if defined(FLASH_BANK2_END)
}
else
{
/* Proceed to program the new data */
SET_BIT(FLASH->CR2, FLASH_CR2_PG);
}
#endif /* FLASH_BANK2_END */
/* Write data in the address */
*(__IO uint16_t*)Address = Data;
}
/**
* @brief Wait for a FLASH operation to complete.
* @param Timeout maximum flash operation timeout
* @retval HAL Status
*/
HAL_StatusTypeDef FLASH_WaitForLastOperation(uint32_t Timeout)
{
/* Wait for the FLASH operation to complete by polling on BUSY flag to be reset.
Even if the FLASH operation fails, the BUSY flag will be reset and an error
flag will be set */
uint32_t tickstart = HAL_GetTick();
while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY))
{
if (Timeout != HAL_MAX_DELAY)
{
if((Timeout == 0U) || ((HAL_GetTick()-tickstart) > Timeout))
{
return HAL_TIMEOUT;
}
}
}
/* Check FLASH End of Operation flag */
if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP))
{
/* Clear FLASH End of Operation pending bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
}
if(__HAL_FLASH_GET_FLAG(FLASH_FLAG_WRPERR) ||
__HAL_FLASH_GET_FLAG(FLASH_FLAG_OPTVERR) ||
__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGERR))
{
/*Save the error code*/
FLASH_SetErrorCode();
return HAL_ERROR;
}
/* There is no error flag set */
return HAL_OK;
}
#if defined(FLASH_BANK2_END)
/**
* @brief Wait for a FLASH BANK2 operation to complete.
* @param Timeout maximum flash operation timeout
* @retval HAL_StatusTypeDef HAL Status
*/
HAL_StatusTypeDef FLASH_WaitForLastOperationBank2(uint32_t Timeout)
{
/* Wait for the FLASH BANK2 operation to complete by polling on BUSY flag to be reset.
Even if the FLASH BANK2 operation fails, the BUSY flag will be reset and an error
flag will be set */
uint32_t tickstart = HAL_GetTick();
while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY_BANK2))
{
if (Timeout != HAL_MAX_DELAY)
{
if((Timeout == 0U) || ((HAL_GetTick()-tickstart) > Timeout))
{
return HAL_TIMEOUT;
}
}
}
/* Check FLASH End of Operation flag */
if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP_BANK2))
{
/* Clear FLASH End of Operation pending bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP_BANK2);
}
if(__HAL_FLASH_GET_FLAG(FLASH_FLAG_WRPERR_BANK2) || __HAL_FLASH_GET_FLAG(FLASH_FLAG_PGERR_BANK2))
{
/*Save the error code*/
FLASH_SetErrorCode();
return HAL_ERROR;
}
/* If there is an error flag set */
return HAL_OK;
}
#endif /* FLASH_BANK2_END */
/**
* @brief Set the specific FLASH error flag.
* @retval None
*/
static void FLASH_SetErrorCode(void)
{
uint32_t flags = 0U;
#if defined(FLASH_BANK2_END)
if(__HAL_FLASH_GET_FLAG(FLASH_FLAG_WRPERR) || __HAL_FLASH_GET_FLAG(FLASH_FLAG_WRPERR_BANK2))
#else
if(__HAL_FLASH_GET_FLAG(FLASH_FLAG_WRPERR))
#endif /* FLASH_BANK2_END */
{
pFlash.ErrorCode |= HAL_FLASH_ERROR_WRP;
#if defined(FLASH_BANK2_END)
flags |= FLASH_FLAG_WRPERR | FLASH_FLAG_WRPERR_BANK2;
#else
flags |= FLASH_FLAG_WRPERR;
#endif /* FLASH_BANK2_END */
}
#if defined(FLASH_BANK2_END)
if(__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGERR) || __HAL_FLASH_GET_FLAG(FLASH_FLAG_PGERR_BANK2))
#else
if(__HAL_FLASH_GET_FLAG(FLASH_FLAG_PGERR))
#endif /* FLASH_BANK2_END */
{
pFlash.ErrorCode |= HAL_FLASH_ERROR_PROG;
#if defined(FLASH_BANK2_END)
flags |= FLASH_FLAG_PGERR | FLASH_FLAG_PGERR_BANK2;
#else
flags |= FLASH_FLAG_PGERR;
#endif /* FLASH_BANK2_END */
}
if(__HAL_FLASH_GET_FLAG(FLASH_FLAG_OPTVERR))
{
pFlash.ErrorCode |= HAL_FLASH_ERROR_OPTV;
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
}
/* Clear FLASH error pending bits */
__HAL_FLASH_CLEAR_FLAG(flags);
}
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_FLASH_MODULE_ENABLED */
/**
* @}
*/

View File

@@ -0,0 +1,1121 @@
/**
******************************************************************************
* @file stm32f1xx_hal_flash_ex.c
* @author MCD Application Team
* @brief Extended FLASH HAL module driver.
*
* This file provides firmware functions to manage the following
* functionalities of the FLASH peripheral:
* + Extended Initialization/de-initialization functions
* + Extended I/O operation functions
* + Extended Peripheral Control functions
*
@verbatim
==============================================================================
##### Flash peripheral extended features #####
==============================================================================
##### How to use this driver #####
==============================================================================
[..] This driver provides functions to configure and program the FLASH memory
of all STM32F1xxx devices. It includes
(++) Set/Reset the write protection
(++) Program the user Option Bytes
(++) Get the Read protection Level
@endverbatim
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file in
* the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
#ifdef HAL_FLASH_MODULE_ENABLED
/** @addtogroup FLASH
* @{
*/
/** @addtogroup FLASH_Private_Variables
* @{
*/
/* Variables used for Erase pages under interruption*/
extern FLASH_ProcessTypeDef pFlash;
/**
* @}
*/
/**
* @}
*/
/** @defgroup FLASHEx FLASHEx
* @brief FLASH HAL Extension module driver
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup FLASHEx_Private_Constants FLASHEx Private Constants
* @{
*/
#define FLASH_POSITION_IWDGSW_BIT FLASH_OBR_IWDG_SW_Pos
#define FLASH_POSITION_OB_USERDATA0_BIT FLASH_OBR_DATA0_Pos
#define FLASH_POSITION_OB_USERDATA1_BIT FLASH_OBR_DATA1_Pos
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/** @defgroup FLASHEx_Private_Macros FLASHEx Private Macros
* @{
*/
/**
* @}
*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup FLASHEx_Private_Functions FLASHEx Private Functions
* @{
*/
/* Erase operations */
static void FLASH_MassErase(uint32_t Banks);
void FLASH_PageErase(uint32_t PageAddress);
/* Option bytes control */
static HAL_StatusTypeDef FLASH_OB_EnableWRP(uint32_t WriteProtectPage);
static HAL_StatusTypeDef FLASH_OB_DisableWRP(uint32_t WriteProtectPage);
static HAL_StatusTypeDef FLASH_OB_RDP_LevelConfig(uint8_t ReadProtectLevel);
static HAL_StatusTypeDef FLASH_OB_UserConfig(uint8_t UserConfig);
static HAL_StatusTypeDef FLASH_OB_ProgramData(uint32_t Address, uint8_t Data);
static uint32_t FLASH_OB_GetWRP(void);
static uint32_t FLASH_OB_GetRDP(void);
static uint8_t FLASH_OB_GetUser(void);
/**
* @}
*/
/* Exported functions ---------------------------------------------------------*/
/** @defgroup FLASHEx_Exported_Functions FLASHEx Exported Functions
* @{
*/
/** @defgroup FLASHEx_Exported_Functions_Group1 FLASHEx Memory Erasing functions
* @brief FLASH Memory Erasing functions
*
@verbatim
==============================================================================
##### FLASH Erasing Programming functions #####
==============================================================================
[..] The FLASH Memory Erasing functions, includes the following functions:
(+) HAL_FLASHEx_Erase: return only when erase has been done
(+) HAL_FLASHEx_Erase_IT: end of erase is done when HAL_FLASH_EndOfOperationCallback
is called with parameter 0xFFFFFFFF
[..] Any operation of erase should follow these steps:
(#) Call the HAL_FLASH_Unlock() function to enable the flash control register and
program memory access.
(#) Call the desired function to erase page.
(#) Call the HAL_FLASH_Lock() to disable the flash program memory access
(recommended to protect the FLASH memory against possible unwanted operation).
@endverbatim
* @{
*/
/**
* @brief Perform a mass erase or erase the specified FLASH memory pages
* @note To correctly run this function, the @ref HAL_FLASH_Unlock() function
* must be called before.
* Call the @ref HAL_FLASH_Lock() to disable the flash memory access
* (recommended to protect the FLASH memory against possible unwanted operation)
* @param[in] pEraseInit pointer to an FLASH_EraseInitTypeDef structure that
* contains the configuration information for the erasing.
*
* @param[out] PageError pointer to variable that
* contains the configuration information on faulty page in case of error
* (0xFFFFFFFF means that all the pages have been correctly erased)
*
* @retval HAL_StatusTypeDef HAL Status
*/
HAL_StatusTypeDef HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *PageError)
{
HAL_StatusTypeDef status = HAL_ERROR;
uint32_t address = 0U;
/* Process Locked */
__HAL_LOCK(&pFlash);
/* Check the parameters */
assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));
if (pEraseInit->TypeErase == FLASH_TYPEERASE_MASSERASE)
{
#if defined(FLASH_BANK2_END)
if (pEraseInit->Banks == FLASH_BANK_BOTH)
{
/* Mass Erase requested for Bank1 and Bank2 */
/* Wait for last operation to be completed */
if ((FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE) == HAL_OK) && \
(FLASH_WaitForLastOperationBank2((uint32_t)FLASH_TIMEOUT_VALUE) == HAL_OK))
{
/*Mass erase to be done*/
FLASH_MassErase(FLASH_BANK_BOTH);
/* Wait for last operation to be completed */
if ((FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE) == HAL_OK) && \
(FLASH_WaitForLastOperationBank2((uint32_t)FLASH_TIMEOUT_VALUE) == HAL_OK))
{
status = HAL_OK;
}
/* If the erase operation is completed, disable the MER Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_MER);
CLEAR_BIT(FLASH->CR2, FLASH_CR2_MER);
}
}
else if (pEraseInit->Banks == FLASH_BANK_2)
{
/* Mass Erase requested for Bank2 */
/* Wait for last operation to be completed */
if (FLASH_WaitForLastOperationBank2((uint32_t)FLASH_TIMEOUT_VALUE) == HAL_OK)
{
/*Mass erase to be done*/
FLASH_MassErase(FLASH_BANK_2);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperationBank2((uint32_t)FLASH_TIMEOUT_VALUE);
/* If the erase operation is completed, disable the MER Bit */
CLEAR_BIT(FLASH->CR2, FLASH_CR2_MER);
}
}
else
#endif /* FLASH_BANK2_END */
{
/* Mass Erase requested for Bank1 */
/* Wait for last operation to be completed */
if (FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE) == HAL_OK)
{
/*Mass erase to be done*/
FLASH_MassErase(FLASH_BANK_1);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
/* If the erase operation is completed, disable the MER Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_MER);
}
}
}
else
{
/* Page Erase is requested */
/* Check the parameters */
assert_param(IS_FLASH_PROGRAM_ADDRESS(pEraseInit->PageAddress));
assert_param(IS_FLASH_NB_PAGES(pEraseInit->PageAddress, pEraseInit->NbPages));
#if defined(FLASH_BANK2_END)
/* Page Erase requested on address located on bank2 */
if(pEraseInit->PageAddress > FLASH_BANK1_END)
{
/* Wait for last operation to be completed */
if (FLASH_WaitForLastOperationBank2((uint32_t)FLASH_TIMEOUT_VALUE) == HAL_OK)
{
/*Initialization of PageError variable*/
*PageError = 0xFFFFFFFFU;
/* Erase by page by page to be done*/
for(address = pEraseInit->PageAddress;
address < (pEraseInit->PageAddress + (pEraseInit->NbPages)*FLASH_PAGE_SIZE);
address += FLASH_PAGE_SIZE)
{
FLASH_PageErase(address);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperationBank2((uint32_t)FLASH_TIMEOUT_VALUE);
/* If the erase operation is completed, disable the PER Bit */
CLEAR_BIT(FLASH->CR2, FLASH_CR2_PER);
if (status != HAL_OK)
{
/* In case of error, stop erase procedure and return the faulty address */
*PageError = address;
break;
}
}
}
}
else
#endif /* FLASH_BANK2_END */
{
/* Page Erase requested on address located on bank1 */
/* Wait for last operation to be completed */
if (FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE) == HAL_OK)
{
/*Initialization of PageError variable*/
*PageError = 0xFFFFFFFFU;
/* Erase page by page to be done*/
for(address = pEraseInit->PageAddress;
address < ((pEraseInit->NbPages * FLASH_PAGE_SIZE) + pEraseInit->PageAddress);
address += FLASH_PAGE_SIZE)
{
FLASH_PageErase(address);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
/* If the erase operation is completed, disable the PER Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_PER);
if (status != HAL_OK)
{
/* In case of error, stop erase procedure and return the faulty address */
*PageError = address;
break;
}
}
}
}
}
/* Process Unlocked */
__HAL_UNLOCK(&pFlash);
return status;
}
/**
* @brief Perform a mass erase or erase the specified FLASH memory pages with interrupt enabled
* @note To correctly run this function, the @ref HAL_FLASH_Unlock() function
* must be called before.
* Call the @ref HAL_FLASH_Lock() to disable the flash memory access
* (recommended to protect the FLASH memory against possible unwanted operation)
* @param pEraseInit pointer to an FLASH_EraseInitTypeDef structure that
* contains the configuration information for the erasing.
*
* @retval HAL_StatusTypeDef HAL Status
*/
HAL_StatusTypeDef HAL_FLASHEx_Erase_IT(FLASH_EraseInitTypeDef *pEraseInit)
{
HAL_StatusTypeDef status = HAL_OK;
/* If procedure already ongoing, reject the next one */
if (pFlash.ProcedureOnGoing != FLASH_PROC_NONE)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));
/* Enable End of FLASH Operation and Error source interrupts */
__HAL_FLASH_ENABLE_IT(FLASH_IT_EOP | FLASH_IT_ERR);
#if defined(FLASH_BANK2_END)
/* Enable End of FLASH Operation and Error source interrupts */
__HAL_FLASH_ENABLE_IT(FLASH_IT_EOP_BANK2 | FLASH_IT_ERR_BANK2);
#endif
if (pEraseInit->TypeErase == FLASH_TYPEERASE_MASSERASE)
{
/*Mass erase to be done*/
pFlash.ProcedureOnGoing = FLASH_PROC_MASSERASE;
FLASH_MassErase(pEraseInit->Banks);
}
else
{
/* Erase by page to be done*/
/* Check the parameters */
assert_param(IS_FLASH_PROGRAM_ADDRESS(pEraseInit->PageAddress));
assert_param(IS_FLASH_NB_PAGES(pEraseInit->PageAddress, pEraseInit->NbPages));
pFlash.ProcedureOnGoing = FLASH_PROC_PAGEERASE;
pFlash.DataRemaining = pEraseInit->NbPages;
pFlash.Address = pEraseInit->PageAddress;
/*Erase 1st page and wait for IT*/
FLASH_PageErase(pEraseInit->PageAddress);
}
return status;
}
/**
* @}
*/
/** @defgroup FLASHEx_Exported_Functions_Group2 Option Bytes Programming functions
* @brief Option Bytes Programming functions
*
@verbatim
==============================================================================
##### Option Bytes Programming functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to control the FLASH
option bytes operations.
@endverbatim
* @{
*/
/**
* @brief Erases the FLASH option bytes.
* @note This functions erases all option bytes except the Read protection (RDP).
* The function @ref HAL_FLASH_Unlock() should be called before to unlock the FLASH interface
* The function @ref HAL_FLASH_OB_Unlock() should be called before to unlock the options bytes
* The function @ref HAL_FLASH_OB_Launch() should be called after to force the reload of the options bytes
* (system reset will occur)
* @retval HAL status
*/
HAL_StatusTypeDef HAL_FLASHEx_OBErase(void)
{
uint8_t rdptmp = OB_RDP_LEVEL_0;
HAL_StatusTypeDef status = HAL_ERROR;
/* Get the actual read protection Option Byte value */
rdptmp = FLASH_OB_GetRDP();
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if(status == HAL_OK)
{
/* Clean the error context */
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
/* If the previous operation is completed, proceed to erase the option bytes */
SET_BIT(FLASH->CR, FLASH_CR_OPTER);
SET_BIT(FLASH->CR, FLASH_CR_STRT);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
/* If the erase operation is completed, disable the OPTER Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_OPTER);
if(status == HAL_OK)
{
/* Restore the last read protection Option Byte value */
status = FLASH_OB_RDP_LevelConfig(rdptmp);
}
}
/* Return the erase status */
return status;
}
/**
* @brief Program option bytes
* @note The function @ref HAL_FLASH_Unlock() should be called before to unlock the FLASH interface
* The function @ref HAL_FLASH_OB_Unlock() should be called before to unlock the options bytes
* The function @ref HAL_FLASH_OB_Launch() should be called after to force the reload of the options bytes
* (system reset will occur)
*
* @param pOBInit pointer to an FLASH_OBInitStruct structure that
* contains the configuration information for the programming.
*
* @retval HAL_StatusTypeDef HAL Status
*/
HAL_StatusTypeDef HAL_FLASHEx_OBProgram(FLASH_OBProgramInitTypeDef *pOBInit)
{
HAL_StatusTypeDef status = HAL_ERROR;
/* Process Locked */
__HAL_LOCK(&pFlash);
/* Check the parameters */
assert_param(IS_OPTIONBYTE(pOBInit->OptionType));
/* Write protection configuration */
if((pOBInit->OptionType & OPTIONBYTE_WRP) == OPTIONBYTE_WRP)
{
assert_param(IS_WRPSTATE(pOBInit->WRPState));
if (pOBInit->WRPState == OB_WRPSTATE_ENABLE)
{
/* Enable of Write protection on the selected page */
status = FLASH_OB_EnableWRP(pOBInit->WRPPage);
}
else
{
/* Disable of Write protection on the selected page */
status = FLASH_OB_DisableWRP(pOBInit->WRPPage);
}
if (status != HAL_OK)
{
/* Process Unlocked */
__HAL_UNLOCK(&pFlash);
return status;
}
}
/* Read protection configuration */
if((pOBInit->OptionType & OPTIONBYTE_RDP) == OPTIONBYTE_RDP)
{
status = FLASH_OB_RDP_LevelConfig(pOBInit->RDPLevel);
if (status != HAL_OK)
{
/* Process Unlocked */
__HAL_UNLOCK(&pFlash);
return status;
}
}
/* USER configuration */
if((pOBInit->OptionType & OPTIONBYTE_USER) == OPTIONBYTE_USER)
{
status = FLASH_OB_UserConfig(pOBInit->USERConfig);
if (status != HAL_OK)
{
/* Process Unlocked */
__HAL_UNLOCK(&pFlash);
return status;
}
}
/* DATA configuration*/
if((pOBInit->OptionType & OPTIONBYTE_DATA) == OPTIONBYTE_DATA)
{
status = FLASH_OB_ProgramData(pOBInit->DATAAddress, pOBInit->DATAData);
if (status != HAL_OK)
{
/* Process Unlocked */
__HAL_UNLOCK(&pFlash);
return status;
}
}
/* Process Unlocked */
__HAL_UNLOCK(&pFlash);
return status;
}
/**
* @brief Get the Option byte configuration
* @param pOBInit pointer to an FLASH_OBInitStruct structure that
* contains the configuration information for the programming.
*
* @retval None
*/
void HAL_FLASHEx_OBGetConfig(FLASH_OBProgramInitTypeDef *pOBInit)
{
pOBInit->OptionType = OPTIONBYTE_WRP | OPTIONBYTE_RDP | OPTIONBYTE_USER;
/*Get WRP*/
pOBInit->WRPPage = FLASH_OB_GetWRP();
/*Get RDP Level*/
pOBInit->RDPLevel = FLASH_OB_GetRDP();
/*Get USER*/
pOBInit->USERConfig = FLASH_OB_GetUser();
}
/**
* @brief Get the Option byte user data
* @param DATAAdress Address of the option byte DATA
* This parameter can be one of the following values:
* @arg @ref OB_DATA_ADDRESS_DATA0
* @arg @ref OB_DATA_ADDRESS_DATA1
* @retval Value programmed in USER data
*/
uint32_t HAL_FLASHEx_OBGetUserData(uint32_t DATAAdress)
{
uint32_t value = 0;
if (DATAAdress == OB_DATA_ADDRESS_DATA0)
{
/* Get value programmed in OB USER Data0 */
value = READ_BIT(FLASH->OBR, FLASH_OBR_DATA0) >> FLASH_POSITION_OB_USERDATA0_BIT;
}
else
{
/* Get value programmed in OB USER Data1 */
value = READ_BIT(FLASH->OBR, FLASH_OBR_DATA1) >> FLASH_POSITION_OB_USERDATA1_BIT;
}
return value;
}
/**
* @}
*/
/**
* @}
*/
/** @addtogroup FLASHEx_Private_Functions
* @{
*/
/**
* @brief Full erase of FLASH memory Bank
* @param Banks Banks to be erased
* This parameter can be one of the following values:
* @arg @ref FLASH_BANK_1 Bank1 to be erased
@if STM32F101xG
* @arg @ref FLASH_BANK_2 Bank2 to be erased
* @arg @ref FLASH_BANK_BOTH Bank1 and Bank2 to be erased
@endif
@if STM32F103xG
* @arg @ref FLASH_BANK_2 Bank2 to be erased
* @arg @ref FLASH_BANK_BOTH Bank1 and Bank2 to be erased
@endif
*
* @retval None
*/
static void FLASH_MassErase(uint32_t Banks)
{
/* Check the parameters */
assert_param(IS_FLASH_BANK(Banks));
/* Clean the error context */
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
#if defined(FLASH_BANK2_END)
if(Banks == FLASH_BANK_BOTH)
{
/* bank1 & bank2 will be erased*/
SET_BIT(FLASH->CR, FLASH_CR_MER);
SET_BIT(FLASH->CR2, FLASH_CR2_MER);
SET_BIT(FLASH->CR, FLASH_CR_STRT);
SET_BIT(FLASH->CR2, FLASH_CR2_STRT);
}
else if(Banks == FLASH_BANK_2)
{
/*Only bank2 will be erased*/
SET_BIT(FLASH->CR2, FLASH_CR2_MER);
SET_BIT(FLASH->CR2, FLASH_CR2_STRT);
}
else
{
#endif /* FLASH_BANK2_END */
#if !defined(FLASH_BANK2_END)
/* Prevent unused argument(s) compilation warning */
UNUSED(Banks);
#endif /* FLASH_BANK2_END */
/* Only bank1 will be erased*/
SET_BIT(FLASH->CR, FLASH_CR_MER);
SET_BIT(FLASH->CR, FLASH_CR_STRT);
#if defined(FLASH_BANK2_END)
}
#endif /* FLASH_BANK2_END */
}
/**
* @brief Enable the write protection of the desired pages
* @note An option byte erase is done automatically in this function.
* @note When the memory read protection level is selected (RDP level = 1),
* it is not possible to program or erase the flash page i if
* debug features are connected or boot code is executed in RAM, even if nWRPi = 1
*
* @param WriteProtectPage specifies the page(s) to be write protected.
* The value of this parameter depend on device used within the same series
* @retval HAL status
*/
static HAL_StatusTypeDef FLASH_OB_EnableWRP(uint32_t WriteProtectPage)
{
HAL_StatusTypeDef status = HAL_OK;
uint16_t WRP0_Data = 0xFFFF;
#if defined(FLASH_WRP1_WRP1)
uint16_t WRP1_Data = 0xFFFF;
#endif /* FLASH_WRP1_WRP1 */
#if defined(FLASH_WRP2_WRP2)
uint16_t WRP2_Data = 0xFFFF;
#endif /* FLASH_WRP2_WRP2 */
#if defined(FLASH_WRP3_WRP3)
uint16_t WRP3_Data = 0xFFFF;
#endif /* FLASH_WRP3_WRP3 */
/* Check the parameters */
assert_param(IS_OB_WRP(WriteProtectPage));
/* Get current write protected pages and the new pages to be protected ******/
WriteProtectPage = (uint32_t)(~((~FLASH_OB_GetWRP()) | WriteProtectPage));
#if defined(OB_WRP_PAGES0TO15MASK)
WRP0_Data = (uint16_t)(WriteProtectPage & OB_WRP_PAGES0TO15MASK);
#elif defined(OB_WRP_PAGES0TO31MASK)
WRP0_Data = (uint16_t)(WriteProtectPage & OB_WRP_PAGES0TO31MASK);
#endif /* OB_WRP_PAGES0TO31MASK */
#if defined(OB_WRP_PAGES16TO31MASK)
WRP1_Data = (uint16_t)((WriteProtectPage & OB_WRP_PAGES16TO31MASK) >> 8U);
#elif defined(OB_WRP_PAGES32TO63MASK)
WRP1_Data = (uint16_t)((WriteProtectPage & OB_WRP_PAGES32TO63MASK) >> 8U);
#endif /* OB_WRP_PAGES32TO63MASK */
#if defined(OB_WRP_PAGES64TO95MASK)
WRP2_Data = (uint16_t)((WriteProtectPage & OB_WRP_PAGES64TO95MASK) >> 16U);
#endif /* OB_WRP_PAGES64TO95MASK */
#if defined(OB_WRP_PAGES32TO47MASK)
WRP2_Data = (uint16_t)((WriteProtectPage & OB_WRP_PAGES32TO47MASK) >> 16U);
#endif /* OB_WRP_PAGES32TO47MASK */
#if defined(OB_WRP_PAGES96TO127MASK)
WRP3_Data = (uint16_t)((WriteProtectPage & OB_WRP_PAGES96TO127MASK) >> 24U);
#elif defined(OB_WRP_PAGES48TO255MASK)
WRP3_Data = (uint16_t)((WriteProtectPage & OB_WRP_PAGES48TO255MASK) >> 24U);
#elif defined(OB_WRP_PAGES48TO511MASK)
WRP3_Data = (uint16_t)((WriteProtectPage & OB_WRP_PAGES48TO511MASK) >> 24U);
#elif defined(OB_WRP_PAGES48TO127MASK)
WRP3_Data = (uint16_t)((WriteProtectPage & OB_WRP_PAGES48TO127MASK) >> 24U);
#endif /* OB_WRP_PAGES96TO127MASK */
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if(status == HAL_OK)
{
/* Clean the error context */
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
/* To be able to write again option byte, need to perform a option byte erase */
status = HAL_FLASHEx_OBErase();
if (status == HAL_OK)
{
/* Enable write protection */
SET_BIT(FLASH->CR, FLASH_CR_OPTPG);
#if defined(FLASH_WRP0_WRP0)
if(WRP0_Data != 0xFFU)
{
OB->WRP0 &= WRP0_Data;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
}
#endif /* FLASH_WRP0_WRP0 */
#if defined(FLASH_WRP1_WRP1)
if((status == HAL_OK) && (WRP1_Data != 0xFFU))
{
OB->WRP1 &= WRP1_Data;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
}
#endif /* FLASH_WRP1_WRP1 */
#if defined(FLASH_WRP2_WRP2)
if((status == HAL_OK) && (WRP2_Data != 0xFFU))
{
OB->WRP2 &= WRP2_Data;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
}
#endif /* FLASH_WRP2_WRP2 */
#if defined(FLASH_WRP3_WRP3)
if((status == HAL_OK) && (WRP3_Data != 0xFFU))
{
OB->WRP3 &= WRP3_Data;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
}
#endif /* FLASH_WRP3_WRP3 */
/* if the program operation is completed, disable the OPTPG Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_OPTPG);
}
}
return status;
}
/**
* @brief Disable the write protection of the desired pages
* @note An option byte erase is done automatically in this function.
* @note When the memory read protection level is selected (RDP level = 1),
* it is not possible to program or erase the flash page i if
* debug features are connected or boot code is executed in RAM, even if nWRPi = 1
*
* @param WriteProtectPage specifies the page(s) to be write unprotected.
* The value of this parameter depend on device used within the same series
* @retval HAL status
*/
static HAL_StatusTypeDef FLASH_OB_DisableWRP(uint32_t WriteProtectPage)
{
HAL_StatusTypeDef status = HAL_OK;
uint16_t WRP0_Data = 0xFFFF;
#if defined(FLASH_WRP1_WRP1)
uint16_t WRP1_Data = 0xFFFF;
#endif /* FLASH_WRP1_WRP1 */
#if defined(FLASH_WRP2_WRP2)
uint16_t WRP2_Data = 0xFFFF;
#endif /* FLASH_WRP2_WRP2 */
#if defined(FLASH_WRP3_WRP3)
uint16_t WRP3_Data = 0xFFFF;
#endif /* FLASH_WRP3_WRP3 */
/* Check the parameters */
assert_param(IS_OB_WRP(WriteProtectPage));
/* Get current write protected pages and the new pages to be unprotected ******/
WriteProtectPage = (FLASH_OB_GetWRP() | WriteProtectPage);
#if defined(OB_WRP_PAGES0TO15MASK)
WRP0_Data = (uint16_t)(WriteProtectPage & OB_WRP_PAGES0TO15MASK);
#elif defined(OB_WRP_PAGES0TO31MASK)
WRP0_Data = (uint16_t)(WriteProtectPage & OB_WRP_PAGES0TO31MASK);
#endif /* OB_WRP_PAGES0TO31MASK */
#if defined(OB_WRP_PAGES16TO31MASK)
WRP1_Data = (uint16_t)((WriteProtectPage & OB_WRP_PAGES16TO31MASK) >> 8U);
#elif defined(OB_WRP_PAGES32TO63MASK)
WRP1_Data = (uint16_t)((WriteProtectPage & OB_WRP_PAGES32TO63MASK) >> 8U);
#endif /* OB_WRP_PAGES32TO63MASK */
#if defined(OB_WRP_PAGES64TO95MASK)
WRP2_Data = (uint16_t)((WriteProtectPage & OB_WRP_PAGES64TO95MASK) >> 16U);
#endif /* OB_WRP_PAGES64TO95MASK */
#if defined(OB_WRP_PAGES32TO47MASK)
WRP2_Data = (uint16_t)((WriteProtectPage & OB_WRP_PAGES32TO47MASK) >> 16U);
#endif /* OB_WRP_PAGES32TO47MASK */
#if defined(OB_WRP_PAGES96TO127MASK)
WRP3_Data = (uint16_t)((WriteProtectPage & OB_WRP_PAGES96TO127MASK) >> 24U);
#elif defined(OB_WRP_PAGES48TO255MASK)
WRP3_Data = (uint16_t)((WriteProtectPage & OB_WRP_PAGES48TO255MASK) >> 24U);
#elif defined(OB_WRP_PAGES48TO511MASK)
WRP3_Data = (uint16_t)((WriteProtectPage & OB_WRP_PAGES48TO511MASK) >> 24U);
#elif defined(OB_WRP_PAGES48TO127MASK)
WRP3_Data = (uint16_t)((WriteProtectPage & OB_WRP_PAGES48TO127MASK) >> 24U);
#endif /* OB_WRP_PAGES96TO127MASK */
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if(status == HAL_OK)
{
/* Clean the error context */
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
/* To be able to write again option byte, need to perform a option byte erase */
status = HAL_FLASHEx_OBErase();
if (status == HAL_OK)
{
SET_BIT(FLASH->CR, FLASH_CR_OPTPG);
#if defined(FLASH_WRP0_WRP0)
if(WRP0_Data != 0xFFU)
{
OB->WRP0 |= WRP0_Data;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
}
#endif /* FLASH_WRP0_WRP0 */
#if defined(FLASH_WRP1_WRP1)
if((status == HAL_OK) && (WRP1_Data != 0xFFU))
{
OB->WRP1 |= WRP1_Data;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
}
#endif /* FLASH_WRP1_WRP1 */
#if defined(FLASH_WRP2_WRP2)
if((status == HAL_OK) && (WRP2_Data != 0xFFU))
{
OB->WRP2 |= WRP2_Data;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
}
#endif /* FLASH_WRP2_WRP2 */
#if defined(FLASH_WRP3_WRP3)
if((status == HAL_OK) && (WRP3_Data != 0xFFU))
{
OB->WRP3 |= WRP3_Data;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
}
#endif /* FLASH_WRP3_WRP3 */
/* if the program operation is completed, disable the OPTPG Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_OPTPG);
}
}
return status;
}
/**
* @brief Set the read protection level.
* @param ReadProtectLevel specifies the read protection level.
* This parameter can be one of the following values:
* @arg @ref OB_RDP_LEVEL_0 No protection
* @arg @ref OB_RDP_LEVEL_1 Read protection of the memory
* @retval HAL status
*/
static HAL_StatusTypeDef FLASH_OB_RDP_LevelConfig(uint8_t ReadProtectLevel)
{
HAL_StatusTypeDef status = HAL_OK;
/* Check the parameters */
assert_param(IS_OB_RDP_LEVEL(ReadProtectLevel));
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if(status == HAL_OK)
{
/* Clean the error context */
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
/* If the previous operation is completed, proceed to erase the option bytes */
SET_BIT(FLASH->CR, FLASH_CR_OPTER);
SET_BIT(FLASH->CR, FLASH_CR_STRT);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
/* If the erase operation is completed, disable the OPTER Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_OPTER);
if(status == HAL_OK)
{
/* Enable the Option Bytes Programming operation */
SET_BIT(FLASH->CR, FLASH_CR_OPTPG);
WRITE_REG(OB->RDP, ReadProtectLevel);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
/* if the program operation is completed, disable the OPTPG Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_OPTPG);
}
}
return status;
}
/**
* @brief Program the FLASH User Option Byte.
* @note Programming of the OB should be performed only after an erase (otherwise PGERR occurs)
* @param UserConfig The FLASH User Option Bytes values FLASH_OBR_IWDG_SW(Bit2),
* FLASH_OBR_nRST_STOP(Bit3),FLASH_OBR_nRST_STDBY(Bit4).
* And BFBF2(Bit5) for STM32F101xG and STM32F103xG .
* @retval HAL status
*/
static HAL_StatusTypeDef FLASH_OB_UserConfig(uint8_t UserConfig)
{
HAL_StatusTypeDef status = HAL_OK;
/* Check the parameters */
assert_param(IS_OB_IWDG_SOURCE((UserConfig&OB_IWDG_SW)));
assert_param(IS_OB_STOP_SOURCE((UserConfig&OB_STOP_NO_RST)));
assert_param(IS_OB_STDBY_SOURCE((UserConfig&OB_STDBY_NO_RST)));
#if defined(FLASH_BANK2_END)
assert_param(IS_OB_BOOT1((UserConfig&OB_BOOT1_SET)));
#endif /* FLASH_BANK2_END */
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if(status == HAL_OK)
{
/* Clean the error context */
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
/* Enable the Option Bytes Programming operation */
SET_BIT(FLASH->CR, FLASH_CR_OPTPG);
#if defined(FLASH_BANK2_END)
OB->USER = (UserConfig | 0xF0U);
#else
OB->USER = (UserConfig | 0x88U);
#endif /* FLASH_BANK2_END */
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
/* if the program operation is completed, disable the OPTPG Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_OPTPG);
}
return status;
}
/**
* @brief Programs a half word at a specified Option Byte Data address.
* @note The function @ref HAL_FLASH_Unlock() should be called before to unlock the FLASH interface
* The function @ref HAL_FLASH_OB_Unlock() should be called before to unlock the options bytes
* The function @ref HAL_FLASH_OB_Launch() should be called after to force the reload of the options bytes
* (system reset will occur)
* Programming of the OB should be performed only after an erase (otherwise PGERR occurs)
* @param Address specifies the address to be programmed.
* This parameter can be 0x1FFFF804 or 0x1FFFF806.
* @param Data specifies the data to be programmed.
* @retval HAL status
*/
static HAL_StatusTypeDef FLASH_OB_ProgramData(uint32_t Address, uint8_t Data)
{
HAL_StatusTypeDef status = HAL_ERROR;
/* Check the parameters */
assert_param(IS_OB_DATA_ADDRESS(Address));
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if(status == HAL_OK)
{
/* Clean the error context */
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
/* Enables the Option Bytes Programming operation */
SET_BIT(FLASH->CR, FLASH_CR_OPTPG);
*(__IO uint16_t*)Address = Data;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
/* If the program operation is completed, disable the OPTPG Bit */
CLEAR_BIT(FLASH->CR, FLASH_CR_OPTPG);
}
/* Return the Option Byte Data Program Status */
return status;
}
/**
* @brief Return the FLASH Write Protection Option Bytes value.
* @retval The FLASH Write Protection Option Bytes value
*/
static uint32_t FLASH_OB_GetWRP(void)
{
/* Return the FLASH write protection Register value */
return (uint32_t)(READ_REG(FLASH->WRPR));
}
/**
* @brief Returns the FLASH Read Protection level.
* @retval FLASH RDP level
* This parameter can be one of the following values:
* @arg @ref OB_RDP_LEVEL_0 No protection
* @arg @ref OB_RDP_LEVEL_1 Read protection of the memory
*/
static uint32_t FLASH_OB_GetRDP(void)
{
uint32_t readstatus = OB_RDP_LEVEL_0;
uint32_t tmp_reg = 0U;
/* Read RDP level bits */
tmp_reg = READ_BIT(FLASH->OBR, FLASH_OBR_RDPRT);
if (tmp_reg == FLASH_OBR_RDPRT)
{
readstatus = OB_RDP_LEVEL_1;
}
else
{
readstatus = OB_RDP_LEVEL_0;
}
return readstatus;
}
/**
* @brief Return the FLASH User Option Byte value.
* @retval The FLASH User Option Bytes values: FLASH_OBR_IWDG_SW(Bit2),
* FLASH_OBR_nRST_STOP(Bit3),FLASH_OBR_nRST_STDBY(Bit4).
* And FLASH_OBR_BFB2(Bit5) for STM32F101xG and STM32F103xG .
*/
static uint8_t FLASH_OB_GetUser(void)
{
/* Return the User Option Byte */
return (uint8_t)((READ_REG(FLASH->OBR) & FLASH_OBR_USER) >> FLASH_POSITION_IWDGSW_BIT);
}
/**
* @}
*/
/**
* @}
*/
/** @addtogroup FLASH
* @{
*/
/** @addtogroup FLASH_Private_Functions
* @{
*/
/**
* @brief Erase the specified FLASH memory page
* @param PageAddress FLASH page to erase
* The value of this parameter depend on device used within the same series
*
* @retval None
*/
void FLASH_PageErase(uint32_t PageAddress)
{
/* Clean the error context */
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
#if defined(FLASH_BANK2_END)
if(PageAddress > FLASH_BANK1_END)
{
/* Proceed to erase the page */
SET_BIT(FLASH->CR2, FLASH_CR2_PER);
WRITE_REG(FLASH->AR2, PageAddress);
SET_BIT(FLASH->CR2, FLASH_CR2_STRT);
}
else
{
#endif /* FLASH_BANK2_END */
/* Proceed to erase the page */
SET_BIT(FLASH->CR, FLASH_CR_PER);
WRITE_REG(FLASH->AR, PageAddress);
SET_BIT(FLASH->CR, FLASH_CR_STRT);
#if defined(FLASH_BANK2_END)
}
#endif /* FLASH_BANK2_END */
}
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_FLASH_MODULE_ENABLED */
/**
* @}
*/

View File

@@ -0,0 +1,586 @@
/**
******************************************************************************
* @file stm32f1xx_hal_gpio.c
* @author MCD Application Team
* @brief GPIO HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the General Purpose Input/Output (GPIO) peripheral:
* + Initialization and de-initialization functions
* + IO operation functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### GPIO Peripheral features #####
==============================================================================
[..]
Subject to the specific hardware characteristics of each I/O port listed in the datasheet, each
port bit of the General Purpose IO (GPIO) Ports, can be individually configured by software
in several modes:
(+) Input mode
(+) Analog mode
(+) Output mode
(+) Alternate function mode
(+) External interrupt/event lines
[..]
During and just after reset, the alternate functions and external interrupt
lines are not active and the I/O ports are configured in input floating mode.
[..]
All GPIO pins have weak internal pull-up and pull-down resistors, which can be
activated or not.
[..]
In Output or Alternate mode, each IO can be configured on open-drain or push-pull
type and the IO speed can be selected depending on the VDD value.
[..]
All ports have external interrupt/event capability. To use external interrupt
lines, the port must be configured in input mode. All available GPIO pins are
connected to the 16 external interrupt/event lines from EXTI0 to EXTI15.
[..]
The external interrupt/event controller consists of up to 20 edge detectors in connectivity
line devices, or 19 edge detectors in other devices for generating event/interrupt requests.
Each input line can be independently configured to select the type (event or interrupt) and
the corresponding trigger event (rising or falling or both). Each line can also masked
independently. A pending register maintains the status line of the interrupt requests
##### How to use this driver #####
==============================================================================
[..]
(#) Enable the GPIO APB2 clock using the following function : __HAL_RCC_GPIOx_CLK_ENABLE().
(#) Configure the GPIO pin(s) using HAL_GPIO_Init().
(++) Configure the IO mode using "Mode" member from GPIO_InitTypeDef structure
(++) Activate Pull-up, Pull-down resistor using "Pull" member from GPIO_InitTypeDef
structure.
(++) In case of Output or alternate function mode selection: the speed is
configured through "Speed" member from GPIO_InitTypeDef structure
(++) Analog mode is required when a pin is to be used as ADC channel
or DAC output.
(++) In case of external interrupt/event selection the "Mode" member from
GPIO_InitTypeDef structure select the type (interrupt or event) and
the corresponding trigger event (rising or falling or both).
(#) In case of external interrupt/event mode selection, configure NVIC IRQ priority
mapped to the EXTI line using HAL_NVIC_SetPriority() and enable it using
HAL_NVIC_EnableIRQ().
(#) To get the level of a pin configured in input mode use HAL_GPIO_ReadPin().
(#) To set/reset the level of a pin configured in output mode use
HAL_GPIO_WritePin()/HAL_GPIO_TogglePin().
(#) To lock pin configuration until next reset use HAL_GPIO_LockPin().
(#) During and just after reset, the alternate functions are not
active and the GPIO pins are configured in input floating mode (except JTAG
pins).
(#) The LSE oscillator pins OSC32_IN and OSC32_OUT can be used as general purpose
(PC14 and PC15, respectively) when the LSE oscillator is off. The LSE has
priority over the GPIO function.
(#) The HSE oscillator pins OSC_IN/OSC_OUT can be used as
general purpose PD0 and PD1, respectively, when the HSE oscillator is off.
The HSE has priority over the GPIO function.
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup GPIO GPIO
* @brief GPIO HAL module driver
* @{
*/
#ifdef HAL_GPIO_MODULE_ENABLED
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @addtogroup GPIO_Private_Constants GPIO Private Constants
* @{
*/
#define GPIO_MODE 0x00000003u
#define EXTI_MODE 0x10000000u
#define GPIO_MODE_IT 0x00010000u
#define GPIO_MODE_EVT 0x00020000u
#define RISING_EDGE 0x00100000u
#define FALLING_EDGE 0x00200000u
#define GPIO_OUTPUT_TYPE 0x00000010u
#define GPIO_NUMBER 16u
/* Definitions for bit manipulation of CRL and CRH register */
#define GPIO_CR_MODE_INPUT 0x00000000u /*!< 00: Input mode (reset state) */
#define GPIO_CR_CNF_ANALOG 0x00000000u /*!< 00: Analog mode */
#define GPIO_CR_CNF_INPUT_FLOATING 0x00000004u /*!< 01: Floating input (reset state) */
#define GPIO_CR_CNF_INPUT_PU_PD 0x00000008u /*!< 10: Input with pull-up / pull-down */
#define GPIO_CR_CNF_GP_OUTPUT_PP 0x00000000u /*!< 00: General purpose output push-pull */
#define GPIO_CR_CNF_GP_OUTPUT_OD 0x00000004u /*!< 01: General purpose output Open-drain */
#define GPIO_CR_CNF_AF_OUTPUT_PP 0x00000008u /*!< 10: Alternate function output Push-pull */
#define GPIO_CR_CNF_AF_OUTPUT_OD 0x0000000Cu /*!< 11: Alternate function output Open-drain */
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup GPIO_Exported_Functions GPIO Exported Functions
* @{
*/
/** @defgroup GPIO_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
===============================================================================
##### Initialization and de-initialization functions #####
===============================================================================
[..]
This section provides functions allowing to initialize and de-initialize the GPIOs
to be ready for use.
@endverbatim
* @{
*/
/**
* @brief Initializes the GPIOx peripheral according to the specified parameters in the GPIO_Init.
* @param GPIOx: where x can be (A..G depending on device used) to select the GPIO peripheral
* @param GPIO_Init: pointer to a GPIO_InitTypeDef structure that contains
* the configuration information for the specified GPIO peripheral.
* @retval None
*/
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
{
uint32_t position = 0x00u;
uint32_t ioposition;
uint32_t iocurrent;
uint32_t temp;
uint32_t config = 0x00u;
__IO uint32_t *configregister; /* Store the address of CRL or CRH register based on pin number */
uint32_t registeroffset; /* offset used during computation of CNF and MODE bits placement inside CRL or CRH register */
/* Check the parameters */
assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Init->Pin));
assert_param(IS_GPIO_MODE(GPIO_Init->Mode));
/* Configure the port pins */
while (((GPIO_Init->Pin) >> position) != 0x00u)
{
/* Get the IO position */
ioposition = (0x01uL << position);
/* Get the current IO position */
iocurrent = (uint32_t)(GPIO_Init->Pin) & ioposition;
if (iocurrent == ioposition)
{
/* Check the Alternate function parameters */
assert_param(IS_GPIO_AF_INSTANCE(GPIOx));
/* Based on the required mode, filling config variable with MODEy[1:0] and CNFy[3:2] corresponding bits */
switch (GPIO_Init->Mode)
{
/* If we are configuring the pin in OUTPUT push-pull mode */
case GPIO_MODE_OUTPUT_PP:
/* Check the GPIO speed parameter */
assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
config = GPIO_Init->Speed + GPIO_CR_CNF_GP_OUTPUT_PP;
break;
/* If we are configuring the pin in OUTPUT open-drain mode */
case GPIO_MODE_OUTPUT_OD:
/* Check the GPIO speed parameter */
assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
config = GPIO_Init->Speed + GPIO_CR_CNF_GP_OUTPUT_OD;
break;
/* If we are configuring the pin in ALTERNATE FUNCTION push-pull mode */
case GPIO_MODE_AF_PP:
/* Check the GPIO speed parameter */
assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
config = GPIO_Init->Speed + GPIO_CR_CNF_AF_OUTPUT_PP;
break;
/* If we are configuring the pin in ALTERNATE FUNCTION open-drain mode */
case GPIO_MODE_AF_OD:
/* Check the GPIO speed parameter */
assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
config = GPIO_Init->Speed + GPIO_CR_CNF_AF_OUTPUT_OD;
break;
/* If we are configuring the pin in INPUT (also applicable to EVENT and IT mode) */
case GPIO_MODE_INPUT:
case GPIO_MODE_IT_RISING:
case GPIO_MODE_IT_FALLING:
case GPIO_MODE_IT_RISING_FALLING:
case GPIO_MODE_EVT_RISING:
case GPIO_MODE_EVT_FALLING:
case GPIO_MODE_EVT_RISING_FALLING:
/* Check the GPIO pull parameter */
assert_param(IS_GPIO_PULL(GPIO_Init->Pull));
if (GPIO_Init->Pull == GPIO_NOPULL)
{
config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_INPUT_FLOATING;
}
else if (GPIO_Init->Pull == GPIO_PULLUP)
{
config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_INPUT_PU_PD;
/* Set the corresponding ODR bit */
GPIOx->BSRR = ioposition;
}
else /* GPIO_PULLDOWN */
{
config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_INPUT_PU_PD;
/* Reset the corresponding ODR bit */
GPIOx->BRR = ioposition;
}
break;
/* If we are configuring the pin in INPUT analog mode */
case GPIO_MODE_ANALOG:
config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_ANALOG;
break;
/* Parameters are checked with assert_param */
default:
break;
}
/* Check if the current bit belongs to first half or last half of the pin count number
in order to address CRH or CRL register*/
configregister = (iocurrent < GPIO_PIN_8) ? &GPIOx->CRL : &GPIOx->CRH;
registeroffset = (iocurrent < GPIO_PIN_8) ? (position << 2u) : ((position - 8u) << 2u);
/* Apply the new configuration of the pin to the register */
MODIFY_REG((*configregister), ((GPIO_CRL_MODE0 | GPIO_CRL_CNF0) << registeroffset), (config << registeroffset));
/*--------------------- EXTI Mode Configuration ------------------------*/
/* Configure the External Interrupt or event for the current IO */
if ((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE)
{
/* Enable AFIO Clock */
__HAL_RCC_AFIO_CLK_ENABLE();
temp = AFIO->EXTICR[position >> 2u];
CLEAR_BIT(temp, (0x0Fu) << (4u * (position & 0x03u)));
SET_BIT(temp, (GPIO_GET_INDEX(GPIOx)) << (4u * (position & 0x03u)));
AFIO->EXTICR[position >> 2u] = temp;
/* Enable or disable the rising trigger */
if ((GPIO_Init->Mode & RISING_EDGE) == RISING_EDGE)
{
SET_BIT(EXTI->RTSR, iocurrent);
}
else
{
CLEAR_BIT(EXTI->RTSR, iocurrent);
}
/* Enable or disable the falling trigger */
if ((GPIO_Init->Mode & FALLING_EDGE) == FALLING_EDGE)
{
SET_BIT(EXTI->FTSR, iocurrent);
}
else
{
CLEAR_BIT(EXTI->FTSR, iocurrent);
}
/* Configure the event mask */
if ((GPIO_Init->Mode & GPIO_MODE_EVT) == GPIO_MODE_EVT)
{
SET_BIT(EXTI->EMR, iocurrent);
}
else
{
CLEAR_BIT(EXTI->EMR, iocurrent);
}
/* Configure the interrupt mask */
if ((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT)
{
SET_BIT(EXTI->IMR, iocurrent);
}
else
{
CLEAR_BIT(EXTI->IMR, iocurrent);
}
}
}
position++;
}
}
/**
* @brief De-initializes the GPIOx peripheral registers to their default reset values.
* @param GPIOx: where x can be (A..G depending on device used) to select the GPIO peripheral
* @param GPIO_Pin: specifies the port bit to be written.
* This parameter can be one of GPIO_PIN_x where x can be (0..15).
* @retval None
*/
void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin)
{
uint32_t position = 0x00u;
uint32_t iocurrent;
uint32_t tmp;
__IO uint32_t *configregister; /* Store the address of CRL or CRH register based on pin number */
uint32_t registeroffset;
/* Check the parameters */
assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));
/* Configure the port pins */
while ((GPIO_Pin >> position) != 0u)
{
/* Get current io position */
iocurrent = (GPIO_Pin) & (1uL << position);
if (iocurrent)
{
/*------------------------- EXTI Mode Configuration --------------------*/
/* Clear the External Interrupt or Event for the current IO */
tmp = AFIO->EXTICR[position >> 2u];
tmp &= 0x0FuL << (4u * (position & 0x03u));
if (tmp == (GPIO_GET_INDEX(GPIOx) << (4u * (position & 0x03u))))
{
/* Clear EXTI line configuration */
CLEAR_BIT(EXTI->IMR, (uint32_t)iocurrent);
CLEAR_BIT(EXTI->EMR, (uint32_t)iocurrent);
/* Clear Rising Falling edge configuration */
CLEAR_BIT(EXTI->FTSR, (uint32_t)iocurrent);
CLEAR_BIT(EXTI->RTSR, (uint32_t)iocurrent);
tmp = 0x0FuL << (4u * (position & 0x03u));
CLEAR_BIT(AFIO->EXTICR[position >> 2u], tmp);
}
/*------------------------- GPIO Mode Configuration --------------------*/
/* Check if the current bit belongs to first half or last half of the pin count number
in order to address CRH or CRL register */
configregister = (iocurrent < GPIO_PIN_8) ? &GPIOx->CRL : &GPIOx->CRH;
registeroffset = (iocurrent < GPIO_PIN_8) ? (position << 2u) : ((position - 8u) << 2u);
/* CRL/CRH default value is floating input(0x04) shifted to correct position */
MODIFY_REG(*configregister, ((GPIO_CRL_MODE0 | GPIO_CRL_CNF0) << registeroffset), GPIO_CRL_CNF0_0 << registeroffset);
/* ODR default value is 0 */
CLEAR_BIT(GPIOx->ODR, iocurrent);
}
position++;
}
}
/**
* @}
*/
/** @defgroup GPIO_Exported_Functions_Group2 IO operation functions
* @brief GPIO Read and Write
*
@verbatim
===============================================================================
##### IO operation functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to manage the GPIOs.
@endverbatim
* @{
*/
/**
* @brief Reads the specified input port pin.
* @param GPIOx: where x can be (A..G depending on device used) to select the GPIO peripheral
* @param GPIO_Pin: specifies the port bit to read.
* This parameter can be GPIO_PIN_x where x can be (0..15).
* @retval The input port pin value.
*/
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
GPIO_PinState bitstatus;
/* Check the parameters */
assert_param(IS_GPIO_PIN(GPIO_Pin));
if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET)
{
bitstatus = GPIO_PIN_SET;
}
else
{
bitstatus = GPIO_PIN_RESET;
}
return bitstatus;
}
/**
* @brief Sets or clears the selected data port bit.
*
* @note This function uses GPIOx_BSRR register to allow atomic read/modify
* accesses. In this way, there is no risk of an IRQ occurring between
* the read and the modify access.
*
* @param GPIOx: where x can be (A..G depending on device used) to select the GPIO peripheral
* @param GPIO_Pin: specifies the port bit to be written.
* This parameter can be one of GPIO_PIN_x where x can be (0..15).
* @param PinState: specifies the value to be written to the selected bit.
* This parameter can be one of the GPIO_PinState enum values:
* @arg GPIO_PIN_RESET: to clear the port pin
* @arg GPIO_PIN_SET: to set the port pin
* @retval None
*/
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
{
/* Check the parameters */
assert_param(IS_GPIO_PIN(GPIO_Pin));
assert_param(IS_GPIO_PIN_ACTION(PinState));
if (PinState != GPIO_PIN_RESET)
{
GPIOx->BSRR = GPIO_Pin;
}
else
{
GPIOx->BSRR = (uint32_t)GPIO_Pin << 16u;
}
}
/**
* @brief Toggles the specified GPIO pin
* @param GPIOx: where x can be (A..G depending on device used) to select the GPIO peripheral
* @param GPIO_Pin: Specifies the pins to be toggled.
* @retval None
*/
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
uint32_t odr;
/* Check the parameters */
assert_param(IS_GPIO_PIN(GPIO_Pin));
/* get current Output Data Register value */
odr = GPIOx->ODR;
/* Set selected pins that were at low level, and reset ones that were high */
GPIOx->BSRR = ((odr & GPIO_Pin) << GPIO_NUMBER) | (~odr & GPIO_Pin);
}
/**
* @brief Locks GPIO Pins configuration registers.
* @note The locking mechanism allows the IO configuration to be frozen. When the LOCK sequence
* has been applied on a port bit, it is no longer possible to modify the value of the port bit until
* the next reset.
* @param GPIOx: where x can be (A..G depending on device used) to select the GPIO peripheral
* @param GPIO_Pin: specifies the port bit to be locked.
* This parameter can be any combination of GPIO_PIN_x where x can be (0..15).
* @retval None
*/
HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
__IO uint32_t tmp = GPIO_LCKR_LCKK;
/* Check the parameters */
assert_param(IS_GPIO_LOCK_INSTANCE(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));
/* Apply lock key write sequence */
SET_BIT(tmp, GPIO_Pin);
/* Set LCKx bit(s): LCKK='1' + LCK[15-0] */
GPIOx->LCKR = tmp;
/* Reset LCKx bit(s): LCKK='0' + LCK[15-0] */
GPIOx->LCKR = GPIO_Pin;
/* Set LCKx bit(s): LCKK='1' + LCK[15-0] */
GPIOx->LCKR = tmp;
/* Read LCKK register. This read is mandatory to complete key lock sequence */
tmp = GPIOx->LCKR;
/* read again in order to confirm lock is active */
if ((uint32_t)(GPIOx->LCKR & GPIO_LCKR_LCKK))
{
return HAL_OK;
}
else
{
return HAL_ERROR;
}
}
/**
* @brief This function handles EXTI interrupt request.
* @param GPIO_Pin: Specifies the pins connected EXTI line
* @retval None
*/
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
/**
* @brief EXTI line detection callbacks.
* @param GPIO_Pin: Specifies the pins connected EXTI line
* @retval None
*/
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(GPIO_Pin);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file
*/
}
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_GPIO_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,126 @@
/**
******************************************************************************
* @file stm32f1xx_hal_gpio_ex.c
* @author MCD Application Team
* @brief GPIO Extension HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the General Purpose Input/Output (GPIO) extension peripheral.
* + Extended features functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### GPIO Peripheral extension features #####
==============================================================================
[..] GPIO module on STM32F1 family, manage also the AFIO register:
(+) Possibility to use the EVENTOUT Cortex feature
##### How to use this driver #####
==============================================================================
[..] This driver provides functions to use EVENTOUT Cortex feature
(#) Configure EVENTOUT Cortex feature using the function HAL_GPIOEx_ConfigEventout()
(#) Activate EVENTOUT Cortex feature using the HAL_GPIOEx_EnableEventout()
(#) Deactivate EVENTOUT Cortex feature using the HAL_GPIOEx_DisableEventout()
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup GPIOEx GPIOEx
* @brief GPIO HAL module driver
* @{
*/
#ifdef HAL_GPIO_MODULE_ENABLED
/** @defgroup GPIOEx_Exported_Functions GPIOEx Exported Functions
* @{
*/
/** @defgroup GPIOEx_Exported_Functions_Group1 Extended features functions
* @brief Extended features functions
*
@verbatim
==============================================================================
##### Extended features functions #####
==============================================================================
[..] This section provides functions allowing to:
(+) Configure EVENTOUT Cortex feature using the function HAL_GPIOEx_ConfigEventout()
(+) Activate EVENTOUT Cortex feature using the HAL_GPIOEx_EnableEventout()
(+) Deactivate EVENTOUT Cortex feature using the HAL_GPIOEx_DisableEventout()
@endverbatim
* @{
*/
/**
* @brief Configures the port and pin on which the EVENTOUT Cortex signal will be connected.
* @param GPIO_PortSource Select the port used to output the Cortex EVENTOUT signal.
* This parameter can be a value of @ref GPIOEx_EVENTOUT_PORT.
* @param GPIO_PinSource Select the pin used to output the Cortex EVENTOUT signal.
* This parameter can be a value of @ref GPIOEx_EVENTOUT_PIN.
* @retval None
*/
void HAL_GPIOEx_ConfigEventout(uint32_t GPIO_PortSource, uint32_t GPIO_PinSource)
{
/* Verify the parameters */
assert_param(IS_AFIO_EVENTOUT_PORT(GPIO_PortSource));
assert_param(IS_AFIO_EVENTOUT_PIN(GPIO_PinSource));
/* Apply the new configuration */
MODIFY_REG(AFIO->EVCR, (AFIO_EVCR_PORT) | (AFIO_EVCR_PIN), (GPIO_PortSource) | (GPIO_PinSource));
}
/**
* @brief Enables the Event Output.
* @retval None
*/
void HAL_GPIOEx_EnableEventout(void)
{
SET_BIT(AFIO->EVCR, AFIO_EVCR_EVOE);
}
/**
* @brief Disables the Event Output.
* @retval None
*/
void HAL_GPIOEx_DisableEventout(void)
{
CLEAR_BIT(AFIO->EVCR, AFIO_EVCR_EVOE);
}
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_GPIO_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,618 @@
/**
******************************************************************************
* @file stm32f1xx_hal_pwr.c
* @author MCD Application Team
* @brief PWR HAL module driver.
*
* This file provides firmware functions to manage the following
* functionalities of the Power Controller (PWR) peripheral:
* + Initialization/de-initialization functions
* + Peripheral Control functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup PWR PWR
* @brief PWR HAL module driver
* @{
*/
#ifdef HAL_PWR_MODULE_ENABLED
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup PWR_Private_Constants PWR Private Constants
* @{
*/
/** @defgroup PWR_PVD_Mode_Mask PWR PVD Mode Mask
* @{
*/
#define PVD_MODE_IT 0x00010000U
#define PVD_MODE_EVT 0x00020000U
#define PVD_RISING_EDGE 0x00000001U
#define PVD_FALLING_EDGE 0x00000002U
/**
* @}
*/
/** @defgroup PWR_register_alias_address PWR Register alias address
* @{
*/
/* ------------- PWR registers bit address in the alias region ---------------*/
#define PWR_OFFSET (PWR_BASE - PERIPH_BASE)
#define PWR_CR_OFFSET 0x00U
#define PWR_CSR_OFFSET 0x04U
#define PWR_CR_OFFSET_BB (PWR_OFFSET + PWR_CR_OFFSET)
#define PWR_CSR_OFFSET_BB (PWR_OFFSET + PWR_CSR_OFFSET)
/**
* @}
*/
/** @defgroup PWR_CR_register_alias PWR CR Register alias address
* @{
*/
/* --- CR Register ---*/
/* Alias word address of LPSDSR bit */
#define LPSDSR_BIT_NUMBER PWR_CR_LPDS_Pos
#define CR_LPSDSR_BB ((uint32_t)(PERIPH_BB_BASE + (PWR_CR_OFFSET_BB * 32U) + (LPSDSR_BIT_NUMBER * 4U)))
/* Alias word address of DBP bit */
#define DBP_BIT_NUMBER PWR_CR_DBP_Pos
#define CR_DBP_BB ((uint32_t)(PERIPH_BB_BASE + (PWR_CR_OFFSET_BB * 32U) + (DBP_BIT_NUMBER * 4U)))
/* Alias word address of PVDE bit */
#define PVDE_BIT_NUMBER PWR_CR_PVDE_Pos
#define CR_PVDE_BB ((uint32_t)(PERIPH_BB_BASE + (PWR_CR_OFFSET_BB * 32U) + (PVDE_BIT_NUMBER * 4U)))
/**
* @}
*/
/** @defgroup PWR_CSR_register_alias PWR CSR Register alias address
* @{
*/
/* --- CSR Register ---*/
/* Alias word address of EWUP1 bit */
#define CSR_EWUP_BB(VAL) ((uint32_t)(PERIPH_BB_BASE + (PWR_CSR_OFFSET_BB * 32U) + (POSITION_VAL(VAL) * 4U)))
/**
* @}
*/
/**
* @}
*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @defgroup PWR_Private_Functions PWR Private Functions
* brief WFE cortex command overloaded for HAL_PWR_EnterSTOPMode usage only (see Workaround section)
* @{
*/
static void PWR_OverloadWfe(void);
/* Private functions ---------------------------------------------------------*/
__NOINLINE
static void PWR_OverloadWfe(void)
{
__asm volatile( "wfe" );
__asm volatile( "nop" );
}
/**
* @}
*/
/** @defgroup PWR_Exported_Functions PWR Exported Functions
* @{
*/
/** @defgroup PWR_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and de-initialization functions
*
@verbatim
===============================================================================
##### Initialization and de-initialization functions #####
===============================================================================
[..]
After reset, the backup domain (RTC registers, RTC backup data
registers) is protected against possible unwanted
write accesses.
To enable access to the RTC Domain and RTC registers, proceed as follows:
(+) Enable the Power Controller (PWR) APB1 interface clock using the
__HAL_RCC_PWR_CLK_ENABLE() macro.
(+) Enable access to RTC domain using the HAL_PWR_EnableBkUpAccess() function.
@endverbatim
* @{
*/
/**
* @brief Deinitializes the PWR peripheral registers to their default reset values.
* @retval None
*/
void HAL_PWR_DeInit(void)
{
__HAL_RCC_PWR_FORCE_RESET();
__HAL_RCC_PWR_RELEASE_RESET();
}
/**
* @brief Enables access to the backup domain (RTC registers, RTC
* backup data registers ).
* @note If the HSE divided by 128 is used as the RTC clock, the
* Backup Domain Access should be kept enabled.
* @retval None
*/
void HAL_PWR_EnableBkUpAccess(void)
{
/* Enable access to RTC and backup registers */
*(__IO uint32_t *) CR_DBP_BB = (uint32_t)ENABLE;
}
/**
* @brief Disables access to the backup domain (RTC registers, RTC
* backup data registers).
* @note If the HSE divided by 128 is used as the RTC clock, the
* Backup Domain Access should be kept enabled.
* @retval None
*/
void HAL_PWR_DisableBkUpAccess(void)
{
/* Disable access to RTC and backup registers */
*(__IO uint32_t *) CR_DBP_BB = (uint32_t)DISABLE;
}
/**
* @}
*/
/** @defgroup PWR_Exported_Functions_Group2 Peripheral Control functions
* @brief Low Power modes configuration functions
*
@verbatim
===============================================================================
##### Peripheral Control functions #####
===============================================================================
*** PVD configuration ***
=========================
[..]
(+) The PVD is used to monitor the VDD power supply by comparing it to a
threshold selected by the PVD Level (PLS[2:0] bits in the PWR_CR).
(+) A PVDO flag is available to indicate if VDD/VDDA is higher or lower
than the PVD threshold. This event is internally connected to the EXTI
line16 and can generate an interrupt if enabled. This is done through
__HAL_PVD_EXTI_ENABLE_IT() macro.
(+) The PVD is stopped in Standby mode.
*** WakeUp pin configuration ***
================================
[..]
(+) WakeUp pin is used to wake up the system from Standby mode. This pin is
forced in input pull-down configuration and is active on rising edges.
(+) There is one WakeUp pin:
WakeUp Pin 1 on PA.00.
[..]
*** Low Power modes configuration ***
=====================================
[..]
The device features 3 low-power modes:
(+) Sleep mode: CPU clock off, all peripherals including Cortex-M3 core peripherals like
NVIC, SysTick, etc. are kept running
(+) Stop mode: All clocks are stopped
(+) Standby mode: 1.8V domain powered off
*** Sleep mode ***
==================
[..]
(+) Entry:
The Sleep mode is entered by using the HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFx)
functions with
(++) PWR_SLEEPENTRY_WFI: enter SLEEP mode with WFI instruction
(++) PWR_SLEEPENTRY_WFE: enter SLEEP mode with WFE instruction
(+) Exit:
(++) WFI entry mode, Any peripheral interrupt acknowledged by the nested vectored interrupt
controller (NVIC) can wake up the device from Sleep mode.
(++) WFE entry mode, Any wakeup event can wake up the device from Sleep mode.
(+++) Any peripheral interrupt w/o NVIC configuration & SEVONPEND bit set in the Cortex (HAL_PWR_EnableSEVOnPend)
(+++) Any EXTI Line (Internal or External) configured in Event mode
*** Stop mode ***
=================
[..]
The Stop mode is based on the Cortex-M3 deepsleep mode combined with peripheral
clock gating. The voltage regulator can be configured either in normal or low-power mode.
In Stop mode, all clocks in the 1.8 V domain are stopped, the PLL, the HSI and the HSE RC
oscillators are disabled. SRAM and register contents are preserved.
In Stop mode, all I/O pins keep the same state as in Run mode.
(+) Entry:
The Stop mode is entered using the HAL_PWR_EnterSTOPMode(PWR_REGULATOR_VALUE, PWR_SLEEPENTRY_WFx )
function with:
(++) PWR_REGULATOR_VALUE= PWR_MAINREGULATOR_ON: Main regulator ON.
(++) PWR_REGULATOR_VALUE= PWR_LOWPOWERREGULATOR_ON: Low Power regulator ON.
(++) PWR_SLEEPENTRY_WFx= PWR_SLEEPENTRY_WFI: enter STOP mode with WFI instruction
(++) PWR_SLEEPENTRY_WFx= PWR_SLEEPENTRY_WFE: enter STOP mode with WFE instruction
(+) Exit:
(++) WFI entry mode, Any EXTI Line (Internal or External) configured in Interrupt mode with NVIC configured
(++) WFE entry mode, Any EXTI Line (Internal or External) configured in Event mode.
*** Standby mode ***
====================
[..]
The Standby mode allows to achieve the lowest power consumption. It is based on the
Cortex-M3 deepsleep mode, with the voltage regulator disabled. The 1.8 V domain is
consequently powered off. The PLL, the HSI oscillator and the HSE oscillator are also
switched off. SRAM and register contents are lost except for registers in the Backup domain
and Standby circuitry
(+) Entry:
(++) The Standby mode is entered using the HAL_PWR_EnterSTANDBYMode() function.
(+) Exit:
(++) WKUP pin rising edge, RTC alarm event rising edge, external Reset in
NRSTpin, IWDG Reset
*** Auto-wakeup (AWU) from low-power mode ***
=============================================
[..]
(+) The MCU can be woken up from low-power mode by an RTC Alarm event,
without depending on an external interrupt (Auto-wakeup mode).
(+) RTC auto-wakeup (AWU) from the Stop and Standby modes
(++) To wake up from the Stop mode with an RTC alarm event, it is necessary to
configure the RTC to generate the RTC alarm using the HAL_RTC_SetAlarm_IT() function.
*** PWR Workarounds linked to Silicon Limitation ***
====================================================
[..]
Below the list of all silicon limitations known on STM32F1xx prouct.
(#)Workarounds Implemented inside PWR HAL Driver
(##)Debugging Stop mode with WFE entry - overloaded the WFE by an internal function
@endverbatim
* @{
*/
/**
* @brief Configures the voltage threshold detected by the Power Voltage Detector(PVD).
* @param sConfigPVD: pointer to an PWR_PVDTypeDef structure that contains the configuration
* information for the PVD.
* @note Refer to the electrical characteristics of your device datasheet for
* more details about the voltage threshold corresponding to each
* detection level.
* @retval None
*/
void HAL_PWR_ConfigPVD(PWR_PVDTypeDef *sConfigPVD)
{
/* Check the parameters */
assert_param(IS_PWR_PVD_LEVEL(sConfigPVD->PVDLevel));
assert_param(IS_PWR_PVD_MODE(sConfigPVD->Mode));
/* Set PLS[7:5] bits according to PVDLevel value */
MODIFY_REG(PWR->CR, PWR_CR_PLS, sConfigPVD->PVDLevel);
/* Clear any previous config. Keep it clear if no event or IT mode is selected */
__HAL_PWR_PVD_EXTI_DISABLE_EVENT();
__HAL_PWR_PVD_EXTI_DISABLE_IT();
__HAL_PWR_PVD_EXTI_DISABLE_FALLING_EDGE();
__HAL_PWR_PVD_EXTI_DISABLE_RISING_EDGE();
/* Configure interrupt mode */
if((sConfigPVD->Mode & PVD_MODE_IT) == PVD_MODE_IT)
{
__HAL_PWR_PVD_EXTI_ENABLE_IT();
}
/* Configure event mode */
if((sConfigPVD->Mode & PVD_MODE_EVT) == PVD_MODE_EVT)
{
__HAL_PWR_PVD_EXTI_ENABLE_EVENT();
}
/* Configure the edge */
if((sConfigPVD->Mode & PVD_RISING_EDGE) == PVD_RISING_EDGE)
{
__HAL_PWR_PVD_EXTI_ENABLE_RISING_EDGE();
}
if((sConfigPVD->Mode & PVD_FALLING_EDGE) == PVD_FALLING_EDGE)
{
__HAL_PWR_PVD_EXTI_ENABLE_FALLING_EDGE();
}
}
/**
* @brief Enables the Power Voltage Detector(PVD).
* @retval None
*/
void HAL_PWR_EnablePVD(void)
{
/* Enable the power voltage detector */
*(__IO uint32_t *) CR_PVDE_BB = (uint32_t)ENABLE;
}
/**
* @brief Disables the Power Voltage Detector(PVD).
* @retval None
*/
void HAL_PWR_DisablePVD(void)
{
/* Disable the power voltage detector */
*(__IO uint32_t *) CR_PVDE_BB = (uint32_t)DISABLE;
}
/**
* @brief Enables the WakeUp PINx functionality.
* @param WakeUpPinx: Specifies the Power Wake-Up pin to enable.
* This parameter can be one of the following values:
* @arg PWR_WAKEUP_PIN1
* @retval None
*/
void HAL_PWR_EnableWakeUpPin(uint32_t WakeUpPinx)
{
/* Check the parameter */
assert_param(IS_PWR_WAKEUP_PIN(WakeUpPinx));
/* Enable the EWUPx pin */
*(__IO uint32_t *) CSR_EWUP_BB(WakeUpPinx) = (uint32_t)ENABLE;
}
/**
* @brief Disables the WakeUp PINx functionality.
* @param WakeUpPinx: Specifies the Power Wake-Up pin to disable.
* This parameter can be one of the following values:
* @arg PWR_WAKEUP_PIN1
* @retval None
*/
void HAL_PWR_DisableWakeUpPin(uint32_t WakeUpPinx)
{
/* Check the parameter */
assert_param(IS_PWR_WAKEUP_PIN(WakeUpPinx));
/* Disable the EWUPx pin */
*(__IO uint32_t *) CSR_EWUP_BB(WakeUpPinx) = (uint32_t)DISABLE;
}
/**
* @brief Enters Sleep mode.
* @note In Sleep mode, all I/O pins keep the same state as in Run mode.
* @param Regulator: Regulator state as no effect in SLEEP mode - allows to support portability from legacy software
* @param SLEEPEntry: Specifies if SLEEP mode is entered with WFI or WFE instruction.
* When WFI entry is used, tick interrupt have to be disabled if not desired as
* the interrupt wake up source.
* This parameter can be one of the following values:
* @arg PWR_SLEEPENTRY_WFI: enter SLEEP mode with WFI instruction
* @arg PWR_SLEEPENTRY_WFE: enter SLEEP mode with WFE instruction
* @retval None
*/
void HAL_PWR_EnterSLEEPMode(uint32_t Regulator, uint8_t SLEEPEntry)
{
/* Check the parameters */
/* No check on Regulator because parameter not used in SLEEP mode */
/* Prevent unused argument(s) compilation warning */
UNUSED(Regulator);
assert_param(IS_PWR_SLEEP_ENTRY(SLEEPEntry));
/* Clear SLEEPDEEP bit of Cortex System Control Register */
CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
/* Select SLEEP mode entry -------------------------------------------------*/
if(SLEEPEntry == PWR_SLEEPENTRY_WFI)
{
/* Request Wait For Interrupt */
__WFI();
}
else
{
/* Request Wait For Event */
__SEV();
__WFE();
__WFE();
}
}
/**
* @brief Enters Stop mode.
* @note In Stop mode, all I/O pins keep the same state as in Run mode.
* @note When exiting Stop mode by using an interrupt or a wakeup event,
* HSI RC oscillator is selected as system clock.
* @note When the voltage regulator operates in low power mode, an additional
* startup delay is incurred when waking up from Stop mode.
* By keeping the internal regulator ON during Stop mode, the consumption
* is higher although the startup time is reduced.
* @param Regulator: Specifies the regulator state in Stop mode.
* This parameter can be one of the following values:
* @arg PWR_MAINREGULATOR_ON: Stop mode with regulator ON
* @arg PWR_LOWPOWERREGULATOR_ON: Stop mode with low power regulator ON
* @param STOPEntry: Specifies if Stop mode in entered with WFI or WFE instruction.
* This parameter can be one of the following values:
* @arg PWR_STOPENTRY_WFI: Enter Stop mode with WFI instruction
* @arg PWR_STOPENTRY_WFE: Enter Stop mode with WFE instruction
* @retval None
*/
void HAL_PWR_EnterSTOPMode(uint32_t Regulator, uint8_t STOPEntry)
{
/* Check the parameters */
assert_param(IS_PWR_REGULATOR(Regulator));
assert_param(IS_PWR_STOP_ENTRY(STOPEntry));
/* Clear PDDS bit in PWR register to specify entering in STOP mode when CPU enter in Deepsleep */
CLEAR_BIT(PWR->CR, PWR_CR_PDDS);
/* Select the voltage regulator mode by setting LPDS bit in PWR register according to Regulator parameter value */
MODIFY_REG(PWR->CR, PWR_CR_LPDS, Regulator);
/* Set SLEEPDEEP bit of Cortex System Control Register */
SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
/* Select Stop mode entry --------------------------------------------------*/
if(STOPEntry == PWR_STOPENTRY_WFI)
{
/* Request Wait For Interrupt */
__WFI();
}
else
{
/* Request Wait For Event */
__SEV();
PWR_OverloadWfe(); /* WFE redefine locally */
PWR_OverloadWfe(); /* WFE redefine locally */
}
/* Reset SLEEPDEEP bit of Cortex System Control Register */
CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
}
/**
* @brief Enters Standby mode.
* @note In Standby mode, all I/O pins are high impedance except for:
* - Reset pad (still available)
* - TAMPER pin if configured for tamper or calibration out.
* - WKUP pin (PA0) if enabled.
* @retval None
*/
void HAL_PWR_EnterSTANDBYMode(void)
{
/* Select Standby mode */
SET_BIT(PWR->CR, PWR_CR_PDDS);
/* Set SLEEPDEEP bit of Cortex System Control Register */
SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
/* This option is used to ensure that store operations are completed */
#if defined ( __CC_ARM)
__force_stores();
#endif
/* Request Wait For Interrupt */
__WFI();
}
/**
* @brief Indicates Sleep-On-Exit when returning from Handler mode to Thread mode.
* @note Set SLEEPONEXIT bit of SCR register. When this bit is set, the processor
* re-enters SLEEP mode when an interruption handling is over.
* Setting this bit is useful when the processor is expected to run only on
* interruptions handling.
* @retval None
*/
void HAL_PWR_EnableSleepOnExit(void)
{
/* Set SLEEPONEXIT bit of Cortex System Control Register */
SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPONEXIT_Msk));
}
/**
* @brief Disables Sleep-On-Exit feature when returning from Handler mode to Thread mode.
* @note Clears SLEEPONEXIT bit of SCR register. When this bit is set, the processor
* re-enters SLEEP mode when an interruption handling is over.
* @retval None
*/
void HAL_PWR_DisableSleepOnExit(void)
{
/* Clear SLEEPONEXIT bit of Cortex System Control Register */
CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPONEXIT_Msk));
}
/**
* @brief Enables CORTEX M3 SEVONPEND bit.
* @note Sets SEVONPEND bit of SCR register. When this bit is set, this causes
* WFE to wake up when an interrupt moves from inactive to pended.
* @retval None
*/
void HAL_PWR_EnableSEVOnPend(void)
{
/* Set SEVONPEND bit of Cortex System Control Register */
SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SEVONPEND_Msk));
}
/**
* @brief Disables CORTEX M3 SEVONPEND bit.
* @note Clears SEVONPEND bit of SCR register. When this bit is set, this causes
* WFE to wake up when an interrupt moves from inactive to pended.
* @retval None
*/
void HAL_PWR_DisableSEVOnPend(void)
{
/* Clear SEVONPEND bit of Cortex System Control Register */
CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SEVONPEND_Msk));
}
/**
* @brief This function handles the PWR PVD interrupt request.
* @note This API should be called under the PVD_IRQHandler().
* @retval None
*/
void HAL_PWR_PVD_IRQHandler(void)
{
/* Check PWR exti flag */
if(__HAL_PWR_PVD_EXTI_GET_FLAG() != RESET)
{
/* PWR PVD interrupt user callback */
HAL_PWR_PVDCallback();
/* Clear PWR Exti pending bit */
__HAL_PWR_PVD_EXTI_CLEAR_FLAG();
}
}
/**
* @brief PWR PVD interrupt callback
* @retval None
*/
__weak void HAL_PWR_PVDCallback(void)
{
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_PWR_PVDCallback could be implemented in the user file
*/
}
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_PWR_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,1400 @@
/**
******************************************************************************
* @file stm32f1xx_hal_rcc.c
* @author MCD Application Team
* @brief RCC HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the Reset and Clock Control (RCC) peripheral:
* + Initialization and de-initialization functions
* + Peripheral Control functions
*
@verbatim
==============================================================================
##### RCC specific features #####
==============================================================================
[..]
After reset the device is running from Internal High Speed oscillator
(HSI 8MHz) with Flash 0 wait state, Flash prefetch buffer is enabled,
and all peripherals are off except internal SRAM, Flash and JTAG.
(+) There is no prescaler on High speed (AHB) and Low speed (APB) buses;
all peripherals mapped on these buses are running at HSI speed.
(+) The clock for all peripherals is switched off, except the SRAM and FLASH.
(+) All GPIOs are in input floating state, except the JTAG pins which
are assigned to be used for debug purpose.
[..] Once the device started from reset, the user application has to:
(+) Configure the clock source to be used to drive the System clock
(if the application needs higher frequency/performance)
(+) Configure the System clock frequency and Flash settings
(+) Configure the AHB and APB buses prescalers
(+) Enable the clock for the peripheral(s) to be used
(+) Configure the clock source(s) for peripherals whose clocks are not
derived from the System clock (I2S, RTC, ADC, USB OTG FS)
##### RCC Limitations #####
==============================================================================
[..]
A delay between an RCC peripheral clock enable and the effective peripheral
enabling should be taken into account in order to manage the peripheral read/write
from/to registers.
(+) This delay depends on the peripheral mapping.
(++) AHB & APB peripherals, 1 dummy read is necessary
[..]
Workarounds:
(#) For AHB & APB peripherals, a dummy read to the peripheral register has been
inserted in each __HAL_RCC_PPP_CLK_ENABLE() macro.
@endverbatim
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file in
* the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup RCC RCC
* @brief RCC HAL module driver
* @{
*/
#ifdef HAL_RCC_MODULE_ENABLED
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup RCC_Private_Constants RCC Private Constants
* @{
*/
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/** @defgroup RCC_Private_Macros RCC Private Macros
* @{
*/
#define MCO1_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define MCO1_GPIO_PORT GPIOA
#define MCO1_PIN GPIO_PIN_8
/**
* @}
*/
/* Private variables ---------------------------------------------------------*/
/** @defgroup RCC_Private_Variables RCC Private Variables
* @{
*/
/**
* @}
*/
/* Private function prototypes -----------------------------------------------*/
static void RCC_Delay(uint32_t mdelay);
/* Exported functions --------------------------------------------------------*/
/** @defgroup RCC_Exported_Functions RCC Exported Functions
* @{
*/
/** @defgroup RCC_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
===============================================================================
##### Initialization and de-initialization functions #####
===============================================================================
[..]
This section provides functions allowing to configure the internal/external oscillators
(HSE, HSI, LSE, LSI, PLL, CSS and MCO) and the System buses clocks (SYSCLK, AHB, APB1
and APB2).
[..] Internal/external clock and PLL configuration
(#) HSI (high-speed internal), 8 MHz factory-trimmed RC used directly or through
the PLL as System clock source.
(#) LSI (low-speed internal), ~40 KHz low consumption RC used as IWDG and/or RTC
clock source.
(#) HSE (high-speed external), 4 to 24 MHz (STM32F100xx) or 4 to 16 MHz (STM32F101x/STM32F102x/STM32F103x) or 3 to 25 MHz (STM32F105x/STM32F107x) crystal oscillator used directly or
through the PLL as System clock source. Can be used also as RTC clock source.
(#) LSE (low-speed external), 32 KHz oscillator used as RTC clock source.
(#) PLL (clocked by HSI or HSE), featuring different output clocks:
(++) The first output is used to generate the high speed system clock (up to 72 MHz for STM32F10xxx or up to 24 MHz for STM32F100xx)
(++) The second output is used to generate the clock for the USB OTG FS (48 MHz)
(#) CSS (Clock security system), once enable using the macro __HAL_RCC_CSS_ENABLE()
and if a HSE clock failure occurs(HSE used directly or through PLL as System
clock source), the System clocks automatically switched to HSI and an interrupt
is generated if enabled. The interrupt is linked to the Cortex-M3 NMI
(Non-Maskable Interrupt) exception vector.
(#) MCO1 (microcontroller clock output), used to output SYSCLK, HSI,
HSE or PLL clock (divided by 2) on PA8 pin + PLL2CLK, PLL3CLK/2, PLL3CLK and XTI for STM32F105x/STM32F107x
[..] System, AHB and APB buses clocks configuration
(#) Several clock sources can be used to drive the System clock (SYSCLK): HSI,
HSE and PLL.
The AHB clock (HCLK) is derived from System clock through configurable
prescaler and used to clock the CPU, memory and peripherals mapped
on AHB bus (DMA, GPIO...). APB1 (PCLK1) and APB2 (PCLK2) clocks are derived
from AHB clock through configurable prescalers and used to clock
the peripherals mapped on these buses. You can use
"HAL_RCC_GetSysClockFreq()" function to retrieve the frequencies of these clocks.
-@- All the peripheral clocks are derived from the System clock (SYSCLK) except:
(+@) RTC: RTC clock can be derived either from the LSI, LSE or HSE clock
divided by 128.
(+@) USB OTG FS and RTC: USB OTG FS require a frequency equal to 48 MHz
to work correctly. This clock is derived of the main PLL through PLL Multiplier.
(+@) I2S interface on STM32F105x/STM32F107x can be derived from PLL3CLK
(+@) IWDG clock which is always the LSI clock.
(#) For STM32F10xxx, the maximum frequency of the SYSCLK and HCLK/PCLK2 is 72 MHz, PCLK1 36 MHz.
For STM32F100xx, the maximum frequency of the SYSCLK and HCLK/PCLK1/PCLK2 is 24 MHz.
Depending on the SYSCLK frequency, the flash latency should be adapted accordingly.
@endverbatim
* @{
*/
/*
Additional consideration on the SYSCLK based on Latency settings:
+-----------------------------------------------+
| Latency | SYSCLK clock frequency (MHz) |
|---------------|-------------------------------|
|0WS(1CPU cycle)| 0 < SYSCLK <= 24 |
|---------------|-------------------------------|
|1WS(2CPU cycle)| 24 < SYSCLK <= 48 |
|---------------|-------------------------------|
|2WS(3CPU cycle)| 48 < SYSCLK <= 72 |
+-----------------------------------------------+
*/
/**
* @brief Resets the RCC clock configuration to the default reset state.
* @note The default reset state of the clock configuration is given below:
* - HSI ON and used as system clock source
* - HSE, PLL, PLL2 and PLL3 are OFF
* - AHB, APB1 and APB2 prescaler set to 1.
* - CSS and MCO1 OFF
* - All interrupts disabled
* - All flags are cleared
* @note This function does not modify the configuration of the
* - Peripheral clocks
* - LSI, LSE and RTC clocks
* @retval HAL_StatusTypeDef
*/
HAL_StatusTypeDef HAL_RCC_DeInit(void)
{
uint32_t tickstart;
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Set HSION bit */
SET_BIT(RCC->CR, RCC_CR_HSION);
/* Wait till HSI is ready */
while (READ_BIT(RCC->CR, RCC_CR_HSIRDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > HSI_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* Set HSITRIM bits to the reset value */
MODIFY_REG(RCC->CR, RCC_CR_HSITRIM, (0x10U << RCC_CR_HSITRIM_Pos));
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Reset CFGR register */
CLEAR_REG(RCC->CFGR);
/* Wait till clock switch is ready */
while (READ_BIT(RCC->CFGR, RCC_CFGR_SWS) != RESET)
{
if ((HAL_GetTick() - tickstart) > CLOCKSWITCH_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* Update the SystemCoreClock global variable */
SystemCoreClock = HSI_VALUE;
/* Adapt Systick interrupt period */
if (HAL_InitTick(uwTickPrio) != HAL_OK)
{
return HAL_ERROR;
}
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Second step is to clear PLLON bit */
CLEAR_BIT(RCC->CR, RCC_CR_PLLON);
/* Wait till PLL is disabled */
while (READ_BIT(RCC->CR, RCC_CR_PLLRDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* Ensure to reset PLLSRC and PLLMUL bits */
CLEAR_REG(RCC->CFGR);
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Reset HSEON & CSSON bits */
CLEAR_BIT(RCC->CR, RCC_CR_HSEON | RCC_CR_CSSON);
/* Wait till HSE is disabled */
while (READ_BIT(RCC->CR, RCC_CR_HSERDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > HSE_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* Reset HSEBYP bit */
CLEAR_BIT(RCC->CR, RCC_CR_HSEBYP);
#if defined(RCC_PLL2_SUPPORT)
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Clear PLL2ON bit */
CLEAR_BIT(RCC->CR, RCC_CR_PLL2ON);
/* Wait till PLL2 is disabled */
while (READ_BIT(RCC->CR, RCC_CR_PLL2RDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLL2_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
#endif /* RCC_PLL2_SUPPORT */
#if defined(RCC_PLLI2S_SUPPORT)
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Clear PLL3ON bit */
CLEAR_BIT(RCC->CR, RCC_CR_PLL3ON);
/* Wait till PLL3 is disabled */
while (READ_BIT(RCC->CR, RCC_CR_PLL3RDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
#endif /* RCC_PLLI2S_SUPPORT */
#if defined(RCC_CFGR2_PREDIV1)
/* Reset CFGR2 register */
CLEAR_REG(RCC->CFGR2);
#endif /* RCC_CFGR2_PREDIV1 */
/* Reset all CSR flags */
SET_BIT(RCC->CSR, RCC_CSR_RMVF);
/* Disable all interrupts */
CLEAR_REG(RCC->CIR);
return HAL_OK;
}
/**
* @brief Initializes the RCC Oscillators according to the specified parameters in the
* RCC_OscInitTypeDef.
* @param RCC_OscInitStruct pointer to an RCC_OscInitTypeDef structure that
* contains the configuration information for the RCC Oscillators.
* @note The PLL is not disabled when used as system clock.
* @note The PLL is not disabled when USB OTG FS clock is enabled (specific to devices with USB FS)
* @note Transitions LSE Bypass to LSE On and LSE On to LSE Bypass are not
* supported by this macro. User should request a transition to LSE Off
* first and then LSE On or LSE Bypass.
* @note Transition HSE Bypass to HSE On and HSE On to HSE Bypass are not
* supported by this macro. User should request a transition to HSE Off
* first and then HSE On or HSE Bypass.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct)
{
uint32_t tickstart;
uint32_t pll_config;
/* Check Null pointer */
if (RCC_OscInitStruct == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_RCC_OSCILLATORTYPE(RCC_OscInitStruct->OscillatorType));
/*------------------------------- HSE Configuration ------------------------*/
if (((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSE) == RCC_OSCILLATORTYPE_HSE)
{
/* Check the parameters */
assert_param(IS_RCC_HSE(RCC_OscInitStruct->HSEState));
/* When the HSE is used as system clock or clock source for PLL in these cases it is not allowed to be disabled */
if ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_HSE)
|| ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_PLLCLK) && (__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSE)))
{
if ((__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) != RESET) && (RCC_OscInitStruct->HSEState == RCC_HSE_OFF))
{
return HAL_ERROR;
}
}
else
{
/* Set the new HSE configuration ---------------------------------------*/
__HAL_RCC_HSE_CONFIG(RCC_OscInitStruct->HSEState);
/* Check the HSE State */
if (RCC_OscInitStruct->HSEState != RCC_HSE_OFF)
{
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till HSE is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > HSE_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
else
{
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till HSE is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > HSE_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
}
}
/*----------------------------- HSI Configuration --------------------------*/
if (((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSI) == RCC_OSCILLATORTYPE_HSI)
{
/* Check the parameters */
assert_param(IS_RCC_HSI(RCC_OscInitStruct->HSIState));
assert_param(IS_RCC_CALIBRATION_VALUE(RCC_OscInitStruct->HSICalibrationValue));
/* Check if HSI is used as system clock or as PLL source when PLL is selected as system clock */
if ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_HSI)
|| ((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_PLLCLK) && (__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSI_DIV2)))
{
/* When HSI is used as system clock it will not disabled */
if ((__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) != RESET) && (RCC_OscInitStruct->HSIState != RCC_HSI_ON))
{
return HAL_ERROR;
}
/* Otherwise, just the calibration is allowed */
else
{
/* Adjusts the Internal High Speed oscillator (HSI) calibration value.*/
__HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue);
}
}
else
{
/* Check the HSI State */
if (RCC_OscInitStruct->HSIState != RCC_HSI_OFF)
{
/* Enable the Internal High Speed oscillator (HSI). */
__HAL_RCC_HSI_ENABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till HSI is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > HSI_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* Adjusts the Internal High Speed oscillator (HSI) calibration value.*/
__HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue);
}
else
{
/* Disable the Internal High Speed oscillator (HSI). */
__HAL_RCC_HSI_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till HSI is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > HSI_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
}
}
/*------------------------------ LSI Configuration -------------------------*/
if (((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_LSI) == RCC_OSCILLATORTYPE_LSI)
{
/* Check the parameters */
assert_param(IS_RCC_LSI(RCC_OscInitStruct->LSIState));
/* Check the LSI State */
if (RCC_OscInitStruct->LSIState != RCC_LSI_OFF)
{
/* Enable the Internal Low Speed oscillator (LSI). */
__HAL_RCC_LSI_ENABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till LSI is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > LSI_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* To have a fully stabilized clock in the specified range, a software delay of 1ms
should be added.*/
RCC_Delay(1);
}
else
{
/* Disable the Internal Low Speed oscillator (LSI). */
__HAL_RCC_LSI_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till LSI is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > LSI_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
}
/*------------------------------ LSE Configuration -------------------------*/
if (((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_LSE) == RCC_OSCILLATORTYPE_LSE)
{
FlagStatus pwrclkchanged = RESET;
/* Check the parameters */
assert_param(IS_RCC_LSE(RCC_OscInitStruct->LSEState));
/* Update LSE configuration in Backup Domain control register */
/* Requires to enable write access to Backup Domain of necessary */
if (__HAL_RCC_PWR_IS_CLK_DISABLED())
{
__HAL_RCC_PWR_CLK_ENABLE();
pwrclkchanged = SET;
}
if (HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP))
{
/* Enable write access to Backup domain */
SET_BIT(PWR->CR, PWR_CR_DBP);
/* Wait for Backup domain Write protection disable */
tickstart = HAL_GetTick();
while (HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP))
{
if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
/* Set the new LSE configuration -----------------------------------------*/
__HAL_RCC_LSE_CONFIG(RCC_OscInitStruct->LSEState);
/* Check the LSE State */
if (RCC_OscInitStruct->LSEState != RCC_LSE_OFF)
{
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till LSE is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
else
{
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till LSE is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
/* Require to disable power clock if necessary */
if (pwrclkchanged == SET)
{
__HAL_RCC_PWR_CLK_DISABLE();
}
}
#if defined(RCC_CR_PLL2ON)
/*-------------------------------- PLL2 Configuration -----------------------*/
/* Check the parameters */
assert_param(IS_RCC_PLL2(RCC_OscInitStruct->PLL2.PLL2State));
if ((RCC_OscInitStruct->PLL2.PLL2State) != RCC_PLL2_NONE)
{
/* This bit can not be cleared if the PLL2 clock is used indirectly as system
clock (i.e. it is used as PLL clock entry that is used as system clock). */
if ((__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSE) && \
(__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_PLLCLK) && \
((READ_BIT(RCC->CFGR2, RCC_CFGR2_PREDIV1SRC)) == RCC_CFGR2_PREDIV1SRC_PLL2))
{
return HAL_ERROR;
}
else
{
if ((RCC_OscInitStruct->PLL2.PLL2State) == RCC_PLL2_ON)
{
/* Check the parameters */
assert_param(IS_RCC_PLL2_MUL(RCC_OscInitStruct->PLL2.PLL2MUL));
assert_param(IS_RCC_HSE_PREDIV2(RCC_OscInitStruct->PLL2.HSEPrediv2Value));
/* Prediv2 can be written only when the PLLI2S is disabled. */
/* Return an error only if new value is different from the programmed value */
if (HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLL3ON) && \
(__HAL_RCC_HSE_GET_PREDIV2() != RCC_OscInitStruct->PLL2.HSEPrediv2Value))
{
return HAL_ERROR;
}
/* Disable the main PLL2. */
__HAL_RCC_PLL2_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL2 is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLL2RDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLL2_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* Configure the HSE prediv2 factor --------------------------------*/
__HAL_RCC_HSE_PREDIV2_CONFIG(RCC_OscInitStruct->PLL2.HSEPrediv2Value);
/* Configure the main PLL2 multiplication factors. */
__HAL_RCC_PLL2_CONFIG(RCC_OscInitStruct->PLL2.PLL2MUL);
/* Enable the main PLL2. */
__HAL_RCC_PLL2_ENABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL2 is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLL2RDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > PLL2_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
else
{
/* Set PREDIV1 source to HSE */
CLEAR_BIT(RCC->CFGR2, RCC_CFGR2_PREDIV1SRC);
/* Disable the main PLL2. */
__HAL_RCC_PLL2_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL2 is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLL2RDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLL2_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
}
}
#endif /* RCC_CR_PLL2ON */
/*-------------------------------- PLL Configuration -----------------------*/
/* Check the parameters */
assert_param(IS_RCC_PLL(RCC_OscInitStruct->PLL.PLLState));
if ((RCC_OscInitStruct->PLL.PLLState) != RCC_PLL_NONE)
{
/* Check if the PLL is used as system clock or not */
if (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_SYSCLKSOURCE_STATUS_PLLCLK)
{
if ((RCC_OscInitStruct->PLL.PLLState) == RCC_PLL_ON)
{
/* Check the parameters */
assert_param(IS_RCC_PLLSOURCE(RCC_OscInitStruct->PLL.PLLSource));
assert_param(IS_RCC_PLL_MUL(RCC_OscInitStruct->PLL.PLLMUL));
/* Disable the main PLL. */
__HAL_RCC_PLL_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* Configure the HSE prediv factor --------------------------------*/
/* It can be written only when the PLL is disabled. Not used in PLL source is different than HSE */
if (RCC_OscInitStruct->PLL.PLLSource == RCC_PLLSOURCE_HSE)
{
/* Check the parameter */
assert_param(IS_RCC_HSE_PREDIV(RCC_OscInitStruct->HSEPredivValue));
#if defined(RCC_CFGR2_PREDIV1SRC)
assert_param(IS_RCC_PREDIV1_SOURCE(RCC_OscInitStruct->Prediv1Source));
/* Set PREDIV1 source */
SET_BIT(RCC->CFGR2, RCC_OscInitStruct->Prediv1Source);
#endif /* RCC_CFGR2_PREDIV1SRC */
/* Set PREDIV1 Value */
__HAL_RCC_HSE_PREDIV_CONFIG(RCC_OscInitStruct->HSEPredivValue);
}
/* Configure the main PLL clock source and multiplication factors. */
__HAL_RCC_PLL_CONFIG(RCC_OscInitStruct->PLL.PLLSource,
RCC_OscInitStruct->PLL.PLLMUL);
/* Enable the main PLL. */
__HAL_RCC_PLL_ENABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
else
{
/* Disable the main PLL. */
__HAL_RCC_PLL_DISABLE();
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till PLL is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLL_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
}
else
{
/* Check if there is a request to disable the PLL used as System clock source */
if ((RCC_OscInitStruct->PLL.PLLState) == RCC_PLL_OFF)
{
return HAL_ERROR;
}
else
{
/* Do not return HAL_ERROR if request repeats the current configuration */
pll_config = RCC->CFGR;
if ((READ_BIT(pll_config, RCC_CFGR_PLLSRC) != RCC_OscInitStruct->PLL.PLLSource) ||
(READ_BIT(pll_config, RCC_CFGR_PLLMULL) != RCC_OscInitStruct->PLL.PLLMUL))
{
return HAL_ERROR;
}
}
}
}
return HAL_OK;
}
/**
* @brief Initializes the CPU, AHB and APB buses clocks according to the specified
* parameters in the RCC_ClkInitStruct.
* @param RCC_ClkInitStruct pointer to an RCC_OscInitTypeDef structure that
* contains the configuration information for the RCC peripheral.
* @param FLatency FLASH Latency
* The value of this parameter depend on device used within the same series
* @note The SystemCoreClock CMSIS variable is used to store System Clock Frequency
* and updated by @ref HAL_RCC_GetHCLKFreq() function called within this function
*
* @note The HSI is used (enabled by hardware) as system clock source after
* start-up from Reset, wake-up from STOP and STANDBY mode, or in case
* of failure of the HSE used directly or indirectly as system clock
* (if the Clock Security System CSS is enabled).
*
* @note A switch from one clock source to another occurs only if the target
* clock source is ready (clock stable after start-up delay or PLL locked).
* If a clock source which is not yet ready is selected, the switch will
* occur when the clock source will be ready.
* You can use @ref HAL_RCC_GetClockConfig() function to know which clock is
* currently used as system clock source.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef *RCC_ClkInitStruct, uint32_t FLatency)
{
uint32_t tickstart;
/* Check Null pointer */
if (RCC_ClkInitStruct == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_RCC_CLOCKTYPE(RCC_ClkInitStruct->ClockType));
assert_param(IS_FLASH_LATENCY(FLatency));
/* To correctly read data from FLASH memory, the number of wait states (LATENCY)
must be correctly programmed according to the frequency of the CPU clock
(HCLK) of the device. */
#if defined(FLASH_ACR_LATENCY)
/* Increasing the number of wait states because of higher CPU frequency */
if (FLatency > __HAL_FLASH_GET_LATENCY())
{
/* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */
__HAL_FLASH_SET_LATENCY(FLatency);
/* Check that the new number of wait states is taken into account to access the Flash
memory by reading the FLASH_ACR register */
if (__HAL_FLASH_GET_LATENCY() != FLatency)
{
return HAL_ERROR;
}
}
#endif /* FLASH_ACR_LATENCY */
/*-------------------------- HCLK Configuration --------------------------*/
if (((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_HCLK) == RCC_CLOCKTYPE_HCLK)
{
/* Set the highest APBx dividers in order to ensure that we do not go through
a non-spec phase whatever we decrease or increase HCLK. */
if (((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK1) == RCC_CLOCKTYPE_PCLK1)
{
MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_HCLK_DIV16);
}
if (((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK2) == RCC_CLOCKTYPE_PCLK2)
{
MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, (RCC_HCLK_DIV16 << 3));
}
/* Set the new HCLK clock divider */
assert_param(IS_RCC_HCLK(RCC_ClkInitStruct->AHBCLKDivider));
MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_ClkInitStruct->AHBCLKDivider);
}
/*------------------------- SYSCLK Configuration ---------------------------*/
if (((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_SYSCLK) == RCC_CLOCKTYPE_SYSCLK)
{
assert_param(IS_RCC_SYSCLKSOURCE(RCC_ClkInitStruct->SYSCLKSource));
/* HSE is selected as System Clock Source */
if (RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_HSE)
{
/* Check the HSE ready flag */
if (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)
{
return HAL_ERROR;
}
}
/* PLL is selected as System Clock Source */
else if (RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_PLLCLK)
{
/* Check the PLL ready flag */
if (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET)
{
return HAL_ERROR;
}
}
/* HSI is selected as System Clock Source */
else
{
/* Check the HSI ready flag */
if (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) == RESET)
{
return HAL_ERROR;
}
}
__HAL_RCC_SYSCLK_CONFIG(RCC_ClkInitStruct->SYSCLKSource);
/* Get Start Tick */
tickstart = HAL_GetTick();
while (__HAL_RCC_GET_SYSCLK_SOURCE() != (RCC_ClkInitStruct->SYSCLKSource << RCC_CFGR_SWS_Pos))
{
if ((HAL_GetTick() - tickstart) > CLOCKSWITCH_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
#if defined(FLASH_ACR_LATENCY)
/* Decreasing the number of wait states because of lower CPU frequency */
if (FLatency < __HAL_FLASH_GET_LATENCY())
{
/* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */
__HAL_FLASH_SET_LATENCY(FLatency);
/* Check that the new number of wait states is taken into account to access the Flash
memory by reading the FLASH_ACR register */
if (__HAL_FLASH_GET_LATENCY() != FLatency)
{
return HAL_ERROR;
}
}
#endif /* FLASH_ACR_LATENCY */
/*-------------------------- PCLK1 Configuration ---------------------------*/
if (((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK1) == RCC_CLOCKTYPE_PCLK1)
{
assert_param(IS_RCC_PCLK(RCC_ClkInitStruct->APB1CLKDivider));
MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_ClkInitStruct->APB1CLKDivider);
}
/*-------------------------- PCLK2 Configuration ---------------------------*/
if (((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK2) == RCC_CLOCKTYPE_PCLK2)
{
assert_param(IS_RCC_PCLK(RCC_ClkInitStruct->APB2CLKDivider));
MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, ((RCC_ClkInitStruct->APB2CLKDivider) << 3));
}
/* Update the SystemCoreClock global variable */
SystemCoreClock = HAL_RCC_GetSysClockFreq() >> AHBPrescTable[(RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos];
/* Configure the source of time base considering new system clocks settings*/
HAL_InitTick(uwTickPrio);
return HAL_OK;
}
/**
* @}
*/
/** @defgroup RCC_Exported_Functions_Group2 Peripheral Control functions
* @brief RCC clocks control functions
*
@verbatim
===============================================================================
##### Peripheral Control functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to control the RCC Clocks
frequencies.
@endverbatim
* @{
*/
/**
* @brief Selects the clock source to output on MCO pin.
* @note MCO pin should be configured in alternate function mode.
* @param RCC_MCOx specifies the output direction for the clock source.
* This parameter can be one of the following values:
* @arg @ref RCC_MCO1 Clock source to output on MCO1 pin(PA8).
* @param RCC_MCOSource specifies the clock source to output.
* This parameter can be one of the following values:
* @arg @ref RCC_MCO1SOURCE_NOCLOCK No clock selected as MCO clock
* @arg @ref RCC_MCO1SOURCE_SYSCLK System clock selected as MCO clock
* @arg @ref RCC_MCO1SOURCE_HSI HSI selected as MCO clock
* @arg @ref RCC_MCO1SOURCE_HSE HSE selected as MCO clock
@if STM32F105xC
* @arg @ref RCC_MCO1SOURCE_PLLCLK PLL clock divided by 2 selected as MCO source
* @arg @ref RCC_MCO1SOURCE_PLL2CLK PLL2 clock selected as MCO source
* @arg @ref RCC_MCO1SOURCE_PLL3CLK_DIV2 PLL3 clock divided by 2 selected as MCO source
* @arg @ref RCC_MCO1SOURCE_EXT_HSE XT1 external 3-25 MHz oscillator clock selected as MCO source
* @arg @ref RCC_MCO1SOURCE_PLL3CLK PLL3 clock selected as MCO source
@endif
@if STM32F107xC
* @arg @ref RCC_MCO1SOURCE_PLLCLK PLL clock divided by 2 selected as MCO source
* @arg @ref RCC_MCO1SOURCE_PLL2CLK PLL2 clock selected as MCO source
* @arg @ref RCC_MCO1SOURCE_PLL3CLK_DIV2 PLL3 clock divided by 2 selected as MCO source
* @arg @ref RCC_MCO1SOURCE_EXT_HSE XT1 external 3-25 MHz oscillator clock selected as MCO source
* @arg @ref RCC_MCO1SOURCE_PLL3CLK PLL3 clock selected as MCO source
@endif
* @param RCC_MCODiv specifies the MCO DIV.
* This parameter can be one of the following values:
* @arg @ref RCC_MCODIV_1 no division applied to MCO clock
* @retval None
*/
void HAL_RCC_MCOConfig(uint32_t RCC_MCOx, uint32_t RCC_MCOSource, uint32_t RCC_MCODiv)
{
GPIO_InitTypeDef gpio = {0U};
/* Check the parameters */
assert_param(IS_RCC_MCO(RCC_MCOx));
assert_param(IS_RCC_MCODIV(RCC_MCODiv));
assert_param(IS_RCC_MCO1SOURCE(RCC_MCOSource));
/* Prevent unused argument(s) compilation warning */
UNUSED(RCC_MCOx);
UNUSED(RCC_MCODiv);
/* Configure the MCO1 pin in alternate function mode */
gpio.Mode = GPIO_MODE_AF_PP;
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
gpio.Pull = GPIO_NOPULL;
gpio.Pin = MCO1_PIN;
/* MCO1 Clock Enable */
MCO1_CLK_ENABLE();
HAL_GPIO_Init(MCO1_GPIO_PORT, &gpio);
/* Configure the MCO clock source */
__HAL_RCC_MCO1_CONFIG(RCC_MCOSource, RCC_MCODiv);
}
/**
* @brief Enables the Clock Security System.
* @note If a failure is detected on the HSE oscillator clock, this oscillator
* is automatically disabled and an interrupt is generated to inform the
* software about the failure (Clock Security System Interrupt, CSSI),
* allowing the MCU to perform rescue operations. The CSSI is linked to
* the Cortex-M3 NMI (Non-Maskable Interrupt) exception vector.
* @retval None
*/
void HAL_RCC_EnableCSS(void)
{
*(__IO uint32_t *) RCC_CR_CSSON_BB = (uint32_t)ENABLE;
}
/**
* @brief Disables the Clock Security System.
* @retval None
*/
void HAL_RCC_DisableCSS(void)
{
*(__IO uint32_t *) RCC_CR_CSSON_BB = (uint32_t)DISABLE;
}
/**
* @brief Returns the SYSCLK frequency
* @note The system frequency computed by this function is not the real
* frequency in the chip. It is calculated based on the predefined
* constant and the selected clock source:
* @note If SYSCLK source is HSI, function returns values based on HSI_VALUE(*)
* @note If SYSCLK source is HSE, function returns a value based on HSE_VALUE
* divided by PREDIV factor(**)
* @note If SYSCLK source is PLL, function returns a value based on HSE_VALUE
* divided by PREDIV factor(**) or HSI_VALUE(*) multiplied by the PLL factor.
* @note (*) HSI_VALUE is a constant defined in stm32f1xx_hal_conf.h file (default value
* 8 MHz) but the real value may vary depending on the variations
* in voltage and temperature.
* @note (**) HSE_VALUE is a constant defined in stm32f1xx_hal_conf.h file (default value
* 8 MHz), user has to ensure that HSE_VALUE is same as the real
* frequency of the crystal used. Otherwise, this function may
* have wrong result.
*
* @note The result of this function could be not correct when using fractional
* value for HSE crystal.
*
* @note This function can be used by the user application to compute the
* baud-rate for the communication peripherals or configure other parameters.
*
* @note Each time SYSCLK changes, this function must be called to update the
* right SYSCLK value. Otherwise, any configuration based on this function will be incorrect.
*
* @retval SYSCLK frequency
*/
uint32_t HAL_RCC_GetSysClockFreq(void)
{
#if defined(RCC_CFGR2_PREDIV1SRC)
static const uint8_t aPLLMULFactorTable[14U] = {0, 0, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 13};
static const uint8_t aPredivFactorTable[16U] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
#else
static const uint8_t aPLLMULFactorTable[16U] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16};
#if defined(RCC_CFGR2_PREDIV1)
static const uint8_t aPredivFactorTable[16U] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
#else
static const uint8_t aPredivFactorTable[2U] = {1, 2};
#endif /*RCC_CFGR2_PREDIV1*/
#endif
uint32_t tmpreg = 0U, prediv = 0U, pllclk = 0U, pllmul = 0U;
uint32_t sysclockfreq = 0U;
#if defined(RCC_CFGR2_PREDIV1SRC)
uint32_t prediv2 = 0U, pll2mul = 0U;
#endif /*RCC_CFGR2_PREDIV1SRC*/
tmpreg = RCC->CFGR;
/* Get SYSCLK source -------------------------------------------------------*/
switch (tmpreg & RCC_CFGR_SWS)
{
case RCC_SYSCLKSOURCE_STATUS_HSE: /* HSE used as system clock */
{
sysclockfreq = HSE_VALUE;
break;
}
case RCC_SYSCLKSOURCE_STATUS_PLLCLK: /* PLL used as system clock */
{
pllmul = aPLLMULFactorTable[(uint32_t)(tmpreg & RCC_CFGR_PLLMULL) >> RCC_CFGR_PLLMULL_Pos];
if ((tmpreg & RCC_CFGR_PLLSRC) != RCC_PLLSOURCE_HSI_DIV2)
{
#if defined(RCC_CFGR2_PREDIV1)
prediv = aPredivFactorTable[(uint32_t)(RCC->CFGR2 & RCC_CFGR2_PREDIV1) >> RCC_CFGR2_PREDIV1_Pos];
#else
prediv = aPredivFactorTable[(uint32_t)(RCC->CFGR & RCC_CFGR_PLLXTPRE) >> RCC_CFGR_PLLXTPRE_Pos];
#endif /*RCC_CFGR2_PREDIV1*/
#if defined(RCC_CFGR2_PREDIV1SRC)
if (HAL_IS_BIT_SET(RCC->CFGR2, RCC_CFGR2_PREDIV1SRC))
{
/* PLL2 selected as Prediv1 source */
/* PLLCLK = PLL2CLK / PREDIV1 * PLLMUL with PLL2CLK = HSE/PREDIV2 * PLL2MUL */
prediv2 = ((RCC->CFGR2 & RCC_CFGR2_PREDIV2) >> RCC_CFGR2_PREDIV2_Pos) + 1;
pll2mul = ((RCC->CFGR2 & RCC_CFGR2_PLL2MUL) >> RCC_CFGR2_PLL2MUL_Pos) + 2;
pllclk = (uint32_t)(((uint64_t)HSE_VALUE * (uint64_t)pll2mul * (uint64_t)pllmul) / ((uint64_t)prediv2 * (uint64_t)prediv));
}
else
{
/* HSE used as PLL clock source : PLLCLK = HSE/PREDIV1 * PLLMUL */
pllclk = (uint32_t)((HSE_VALUE * pllmul) / prediv);
}
/* If PLLMUL was set to 13 means that it was to cover the case PLLMUL 6.5 (avoid using float) */
/* In this case need to divide pllclk by 2 */
if (pllmul == aPLLMULFactorTable[(uint32_t)(RCC_CFGR_PLLMULL6_5) >> RCC_CFGR_PLLMULL_Pos])
{
pllclk = pllclk / 2;
}
#else
/* HSE used as PLL clock source : PLLCLK = HSE/PREDIV1 * PLLMUL */
pllclk = (uint32_t)((HSE_VALUE * pllmul) / prediv);
#endif /*RCC_CFGR2_PREDIV1SRC*/
}
else
{
/* HSI used as PLL clock source : PLLCLK = HSI/2 * PLLMUL */
pllclk = (uint32_t)((HSI_VALUE >> 1) * pllmul);
}
sysclockfreq = pllclk;
break;
}
case RCC_SYSCLKSOURCE_STATUS_HSI: /* HSI used as system clock source */
default: /* HSI used as system clock */
{
sysclockfreq = HSI_VALUE;
break;
}
}
return sysclockfreq;
}
/**
* @brief Returns the HCLK frequency
* @note Each time HCLK changes, this function must be called to update the
* right HCLK value. Otherwise, any configuration based on this function will be incorrect.
*
* @note The SystemCoreClock CMSIS variable is used to store System Clock Frequency
* and updated within this function
* @retval HCLK frequency
*/
uint32_t HAL_RCC_GetHCLKFreq(void)
{
return SystemCoreClock;
}
/**
* @brief Returns the PCLK1 frequency
* @note Each time PCLK1 changes, this function must be called to update the
* right PCLK1 value. Otherwise, any configuration based on this function will be incorrect.
* @retval PCLK1 frequency
*/
uint32_t HAL_RCC_GetPCLK1Freq(void)
{
/* Get HCLK source and Compute PCLK1 frequency ---------------------------*/
return (HAL_RCC_GetHCLKFreq() >> APBPrescTable[(RCC->CFGR & RCC_CFGR_PPRE1) >> RCC_CFGR_PPRE1_Pos]);
}
/**
* @brief Returns the PCLK2 frequency
* @note Each time PCLK2 changes, this function must be called to update the
* right PCLK2 value. Otherwise, any configuration based on this function will be incorrect.
* @retval PCLK2 frequency
*/
uint32_t HAL_RCC_GetPCLK2Freq(void)
{
/* Get HCLK source and Compute PCLK2 frequency ---------------------------*/
return (HAL_RCC_GetHCLKFreq() >> APBPrescTable[(RCC->CFGR & RCC_CFGR_PPRE2) >> RCC_CFGR_PPRE2_Pos]);
}
/**
* @brief Configures the RCC_OscInitStruct according to the internal
* RCC configuration registers.
* @param RCC_OscInitStruct pointer to an RCC_OscInitTypeDef structure that
* will be configured.
* @retval None
*/
void HAL_RCC_GetOscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct)
{
/* Check the parameters */
assert_param(RCC_OscInitStruct != NULL);
/* Set all possible values for the Oscillator type parameter ---------------*/
RCC_OscInitStruct->OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI \
| RCC_OSCILLATORTYPE_LSE | RCC_OSCILLATORTYPE_LSI;
#if defined(RCC_CFGR2_PREDIV1SRC)
/* Get the Prediv1 source --------------------------------------------------*/
RCC_OscInitStruct->Prediv1Source = READ_BIT(RCC->CFGR2, RCC_CFGR2_PREDIV1SRC);
#endif /* RCC_CFGR2_PREDIV1SRC */
/* Get the HSE configuration -----------------------------------------------*/
if ((RCC->CR & RCC_CR_HSEBYP) == RCC_CR_HSEBYP)
{
RCC_OscInitStruct->HSEState = RCC_HSE_BYPASS;
}
else if ((RCC->CR & RCC_CR_HSEON) == RCC_CR_HSEON)
{
RCC_OscInitStruct->HSEState = RCC_HSE_ON;
}
else
{
RCC_OscInitStruct->HSEState = RCC_HSE_OFF;
}
RCC_OscInitStruct->HSEPredivValue = __HAL_RCC_HSE_GET_PREDIV();
/* Get the HSI configuration -----------------------------------------------*/
if ((RCC->CR & RCC_CR_HSION) == RCC_CR_HSION)
{
RCC_OscInitStruct->HSIState = RCC_HSI_ON;
}
else
{
RCC_OscInitStruct->HSIState = RCC_HSI_OFF;
}
RCC_OscInitStruct->HSICalibrationValue = (uint32_t)((RCC->CR & RCC_CR_HSITRIM) >> RCC_CR_HSITRIM_Pos);
/* Get the LSE configuration -----------------------------------------------*/
if ((RCC->BDCR & RCC_BDCR_LSEBYP) == RCC_BDCR_LSEBYP)
{
RCC_OscInitStruct->LSEState = RCC_LSE_BYPASS;
}
else if ((RCC->BDCR & RCC_BDCR_LSEON) == RCC_BDCR_LSEON)
{
RCC_OscInitStruct->LSEState = RCC_LSE_ON;
}
else
{
RCC_OscInitStruct->LSEState = RCC_LSE_OFF;
}
/* Get the LSI configuration -----------------------------------------------*/
if ((RCC->CSR & RCC_CSR_LSION) == RCC_CSR_LSION)
{
RCC_OscInitStruct->LSIState = RCC_LSI_ON;
}
else
{
RCC_OscInitStruct->LSIState = RCC_LSI_OFF;
}
/* Get the PLL configuration -----------------------------------------------*/
if ((RCC->CR & RCC_CR_PLLON) == RCC_CR_PLLON)
{
RCC_OscInitStruct->PLL.PLLState = RCC_PLL_ON;
}
else
{
RCC_OscInitStruct->PLL.PLLState = RCC_PLL_OFF;
}
RCC_OscInitStruct->PLL.PLLSource = (uint32_t)(RCC->CFGR & RCC_CFGR_PLLSRC);
RCC_OscInitStruct->PLL.PLLMUL = (uint32_t)(RCC->CFGR & RCC_CFGR_PLLMULL);
#if defined(RCC_CR_PLL2ON)
/* Get the PLL2 configuration -----------------------------------------------*/
if ((RCC->CR & RCC_CR_PLL2ON) == RCC_CR_PLL2ON)
{
RCC_OscInitStruct->PLL2.PLL2State = RCC_PLL2_ON;
}
else
{
RCC_OscInitStruct->PLL2.PLL2State = RCC_PLL2_OFF;
}
RCC_OscInitStruct->PLL2.HSEPrediv2Value = __HAL_RCC_HSE_GET_PREDIV2();
RCC_OscInitStruct->PLL2.PLL2MUL = (uint32_t)(RCC->CFGR2 & RCC_CFGR2_PLL2MUL);
#endif /* RCC_CR_PLL2ON */
}
/**
* @brief Get the RCC_ClkInitStruct according to the internal
* RCC configuration registers.
* @param RCC_ClkInitStruct pointer to an RCC_ClkInitTypeDef structure that
* contains the current clock configuration.
* @param pFLatency Pointer on the Flash Latency.
* @retval None
*/
void HAL_RCC_GetClockConfig(RCC_ClkInitTypeDef *RCC_ClkInitStruct, uint32_t *pFLatency)
{
/* Check the parameters */
assert_param(RCC_ClkInitStruct != NULL);
assert_param(pFLatency != NULL);
/* Set all possible values for the Clock type parameter --------------------*/
RCC_ClkInitStruct->ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
/* Get the SYSCLK configuration --------------------------------------------*/
RCC_ClkInitStruct->SYSCLKSource = (uint32_t)(RCC->CFGR & RCC_CFGR_SW);
/* Get the HCLK configuration ----------------------------------------------*/
RCC_ClkInitStruct->AHBCLKDivider = (uint32_t)(RCC->CFGR & RCC_CFGR_HPRE);
/* Get the APB1 configuration ----------------------------------------------*/
RCC_ClkInitStruct->APB1CLKDivider = (uint32_t)(RCC->CFGR & RCC_CFGR_PPRE1);
/* Get the APB2 configuration ----------------------------------------------*/
RCC_ClkInitStruct->APB2CLKDivider = (uint32_t)((RCC->CFGR & RCC_CFGR_PPRE2) >> 3);
#if defined(FLASH_ACR_LATENCY)
/* Get the Flash Wait State (Latency) configuration ------------------------*/
*pFLatency = (uint32_t)(FLASH->ACR & FLASH_ACR_LATENCY);
#else
/* For VALUE lines devices, only LATENCY_0 can be set*/
*pFLatency = (uint32_t)FLASH_LATENCY_0;
#endif
}
/**
* @brief This function handles the RCC CSS interrupt request.
* @note This API should be called under the NMI_Handler().
* @retval None
*/
void HAL_RCC_NMI_IRQHandler(void)
{
/* Check RCC CSSF flag */
if (__HAL_RCC_GET_IT(RCC_IT_CSS))
{
/* RCC Clock Security System interrupt user callback */
HAL_RCC_CSSCallback();
/* Clear RCC CSS pending bit */
__HAL_RCC_CLEAR_IT(RCC_IT_CSS);
}
}
/**
* @brief This function provides delay (in milliseconds) based on CPU cycles method.
* @param mdelay: specifies the delay time length, in milliseconds.
* @retval None
*/
static void RCC_Delay(uint32_t mdelay)
{
__IO uint32_t Delay = mdelay * (SystemCoreClock / 8U / 1000U);
do
{
__NOP();
}
while (Delay --);
}
/**
* @brief RCC Clock Security System interrupt callback
* @retval none
*/
__weak void HAL_RCC_CSSCallback(void)
{
/* NOTE : This function Should not be modified, when the callback is needed,
the HAL_RCC_CSSCallback could be implemented in the user file
*/
}
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_RCC_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,860 @@
/**
******************************************************************************
* @file stm32f1xx_hal_rcc_ex.c
* @author MCD Application Team
* @brief Extended RCC HAL module driver.
* This file provides firmware functions to manage the following
* functionalities RCC extension peripheral:
* + Extended Peripheral Control functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file in
* the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
#ifdef HAL_RCC_MODULE_ENABLED
/** @defgroup RCCEx RCCEx
* @brief RCC Extension HAL module driver.
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup RCCEx_Private_Constants RCCEx Private Constants
* @{
*/
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/** @defgroup RCCEx_Private_Macros RCCEx Private Macros
* @{
*/
/**
* @}
*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup RCCEx_Exported_Functions RCCEx Exported Functions
* @{
*/
/** @defgroup RCCEx_Exported_Functions_Group1 Peripheral Control functions
* @brief Extended Peripheral Control functions
*
@verbatim
===============================================================================
##### Extended Peripheral Control functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to control the RCC Clocks
frequencies.
[..]
(@) Important note: Care must be taken when HAL_RCCEx_PeriphCLKConfig() is used to
select the RTC clock source; in this case the Backup domain will be reset in
order to modify the RTC Clock source, as consequence RTC registers (including
the backup registers) are set to their reset values.
@endverbatim
* @{
*/
/**
* @brief Initializes the RCC extended peripherals clocks according to the specified parameters in the
* RCC_PeriphCLKInitTypeDef.
* @param PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
* contains the configuration information for the Extended Peripherals clocks(RTC clock).
*
* @note Care must be taken when HAL_RCCEx_PeriphCLKConfig() is used to select
* the RTC clock source; in this case the Backup domain will be reset in
* order to modify the RTC Clock source, as consequence RTC registers (including
* the backup registers) are set to their reset values.
*
* @note In case of STM32F105xC or STM32F107xC devices, PLLI2S will be enabled if requested on
* one of 2 I2S interfaces. When PLLI2S is enabled, you need to call HAL_RCCEx_DisablePLLI2S to
* manually disable it.
*
* @retval HAL status
*/
HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef *PeriphClkInit)
{
uint32_t tickstart = 0U, temp_reg = 0U;
#if defined(STM32F105xC) || defined(STM32F107xC)
uint32_t pllactive = 0U;
#endif /* STM32F105xC || STM32F107xC */
/* Check the parameters */
assert_param(IS_RCC_PERIPHCLOCK(PeriphClkInit->PeriphClockSelection));
/*------------------------------- RTC/LCD Configuration ------------------------*/
if ((((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_RTC) == RCC_PERIPHCLK_RTC))
{
FlagStatus pwrclkchanged = RESET;
/* check for RTC Parameters used to output RTCCLK */
assert_param(IS_RCC_RTCCLKSOURCE(PeriphClkInit->RTCClockSelection));
/* As soon as function is called to change RTC clock source, activation of the
power domain is done. */
/* Requires to enable write access to Backup Domain of necessary */
if (__HAL_RCC_PWR_IS_CLK_DISABLED())
{
__HAL_RCC_PWR_CLK_ENABLE();
pwrclkchanged = SET;
}
if (HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP))
{
/* Enable write access to Backup domain */
SET_BIT(PWR->CR, PWR_CR_DBP);
/* Wait for Backup domain Write protection disable */
tickstart = HAL_GetTick();
while (HAL_IS_BIT_CLR(PWR->CR, PWR_CR_DBP))
{
if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
/* Reset the Backup domain only if the RTC Clock source selection is modified from reset value */
temp_reg = (RCC->BDCR & RCC_BDCR_RTCSEL);
if ((temp_reg != 0x00000000U) && (temp_reg != (PeriphClkInit->RTCClockSelection & RCC_BDCR_RTCSEL)))
{
/* Store the content of BDCR register before the reset of Backup Domain */
temp_reg = (RCC->BDCR & ~(RCC_BDCR_RTCSEL));
/* RTC Clock selection can be changed only if the Backup Domain is reset */
__HAL_RCC_BACKUPRESET_FORCE();
__HAL_RCC_BACKUPRESET_RELEASE();
/* Restore the Content of BDCR register */
RCC->BDCR = temp_reg;
/* Wait for LSERDY if LSE was enabled */
if (HAL_IS_BIT_SET(temp_reg, RCC_BDCR_LSEON))
{
/* Get Start Tick */
tickstart = HAL_GetTick();
/* Wait till LSE is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
}
__HAL_RCC_RTC_CONFIG(PeriphClkInit->RTCClockSelection);
/* Require to disable power clock if necessary */
if (pwrclkchanged == SET)
{
__HAL_RCC_PWR_CLK_DISABLE();
}
}
/*------------------------------ ADC clock Configuration ------------------*/
if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_ADC) == RCC_PERIPHCLK_ADC)
{
/* Check the parameters */
assert_param(IS_RCC_ADCPLLCLK_DIV(PeriphClkInit->AdcClockSelection));
/* Configure the ADC clock source */
__HAL_RCC_ADC_CONFIG(PeriphClkInit->AdcClockSelection);
}
#if defined(STM32F105xC) || defined(STM32F107xC)
/*------------------------------ I2S2 Configuration ------------------------*/
if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S2) == RCC_PERIPHCLK_I2S2)
{
/* Check the parameters */
assert_param(IS_RCC_I2S2CLKSOURCE(PeriphClkInit->I2s2ClockSelection));
/* Configure the I2S2 clock source */
__HAL_RCC_I2S2_CONFIG(PeriphClkInit->I2s2ClockSelection);
}
/*------------------------------ I2S3 Configuration ------------------------*/
if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_I2S3) == RCC_PERIPHCLK_I2S3)
{
/* Check the parameters */
assert_param(IS_RCC_I2S3CLKSOURCE(PeriphClkInit->I2s3ClockSelection));
/* Configure the I2S3 clock source */
__HAL_RCC_I2S3_CONFIG(PeriphClkInit->I2s3ClockSelection);
}
/*------------------------------ PLL I2S Configuration ----------------------*/
/* Check that PLLI2S need to be enabled */
if (HAL_IS_BIT_SET(RCC->CFGR2, RCC_CFGR2_I2S2SRC) || HAL_IS_BIT_SET(RCC->CFGR2, RCC_CFGR2_I2S3SRC))
{
/* Update flag to indicate that PLL I2S should be active */
pllactive = 1;
}
/* Check if PLL I2S need to be enabled */
if (pllactive == 1)
{
/* Enable PLL I2S only if not active */
if (HAL_IS_BIT_CLR(RCC->CR, RCC_CR_PLL3ON))
{
/* Check the parameters */
assert_param(IS_RCC_PLLI2S_MUL(PeriphClkInit->PLLI2S.PLLI2SMUL));
assert_param(IS_RCC_HSE_PREDIV2(PeriphClkInit->PLLI2S.HSEPrediv2Value));
/* Prediv2 can be written only when the PLL2 is disabled. */
/* Return an error only if new value is different from the programmed value */
if (HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLL2ON) && \
(__HAL_RCC_HSE_GET_PREDIV2() != PeriphClkInit->PLLI2S.HSEPrediv2Value))
{
return HAL_ERROR;
}
/* Configure the HSE prediv2 factor --------------------------------*/
__HAL_RCC_HSE_PREDIV2_CONFIG(PeriphClkInit->PLLI2S.HSEPrediv2Value);
/* Configure the main PLLI2S multiplication factors. */
__HAL_RCC_PLLI2S_CONFIG(PeriphClkInit->PLLI2S.PLLI2SMUL);
/* Enable the main PLLI2S. */
__HAL_RCC_PLLI2S_ENABLE();
/* Get Start Tick*/
tickstart = HAL_GetTick();
/* Wait till PLLI2S is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
else
{
/* Return an error only if user wants to change the PLLI2SMUL whereas PLLI2S is active */
if (READ_BIT(RCC->CFGR2, RCC_CFGR2_PLL3MUL) != PeriphClkInit->PLLI2S.PLLI2SMUL)
{
return HAL_ERROR;
}
}
}
#endif /* STM32F105xC || STM32F107xC */
#if defined(STM32F102x6) || defined(STM32F102xB) || defined(STM32F103x6)\
|| defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG)\
|| defined(STM32F105xC) || defined(STM32F107xC)
/*------------------------------ USB clock Configuration ------------------*/
if (((PeriphClkInit->PeriphClockSelection) & RCC_PERIPHCLK_USB) == RCC_PERIPHCLK_USB)
{
/* Check the parameters */
assert_param(IS_RCC_USBPLLCLK_DIV(PeriphClkInit->UsbClockSelection));
/* Configure the USB clock source */
__HAL_RCC_USB_CONFIG(PeriphClkInit->UsbClockSelection);
}
#endif /* STM32F102x6 || STM32F102xB || STM32F103x6 || STM32F103xB || STM32F103xE || STM32F103xG || STM32F105xC || STM32F107xC */
return HAL_OK;
}
/**
* @brief Get the PeriphClkInit according to the internal
* RCC configuration registers.
* @param PeriphClkInit pointer to an RCC_PeriphCLKInitTypeDef structure that
* returns the configuration information for the Extended Peripherals clocks(RTC, I2S, ADC clocks).
* @retval None
*/
void HAL_RCCEx_GetPeriphCLKConfig(RCC_PeriphCLKInitTypeDef *PeriphClkInit)
{
uint32_t srcclk = 0U;
/* Set all possible values for the extended clock type parameter------------*/
PeriphClkInit->PeriphClockSelection = RCC_PERIPHCLK_RTC;
/* Get the RTC configuration -----------------------------------------------*/
srcclk = __HAL_RCC_GET_RTC_SOURCE();
/* Source clock is LSE or LSI*/
PeriphClkInit->RTCClockSelection = srcclk;
/* Get the ADC clock configuration -----------------------------------------*/
PeriphClkInit->PeriphClockSelection |= RCC_PERIPHCLK_ADC;
PeriphClkInit->AdcClockSelection = __HAL_RCC_GET_ADC_SOURCE();
#if defined(STM32F105xC) || defined(STM32F107xC)
/* Get the I2S2 clock configuration -----------------------------------------*/
PeriphClkInit->PeriphClockSelection |= RCC_PERIPHCLK_I2S2;
PeriphClkInit->I2s2ClockSelection = __HAL_RCC_GET_I2S2_SOURCE();
/* Get the I2S3 clock configuration -----------------------------------------*/
PeriphClkInit->PeriphClockSelection |= RCC_PERIPHCLK_I2S3;
PeriphClkInit->I2s3ClockSelection = __HAL_RCC_GET_I2S3_SOURCE();
#endif /* STM32F105xC || STM32F107xC */
#if defined(STM32F103xE) || defined(STM32F103xG)
/* Get the I2S2 clock configuration -----------------------------------------*/
PeriphClkInit->PeriphClockSelection |= RCC_PERIPHCLK_I2S2;
PeriphClkInit->I2s2ClockSelection = RCC_I2S2CLKSOURCE_SYSCLK;
/* Get the I2S3 clock configuration -----------------------------------------*/
PeriphClkInit->PeriphClockSelection |= RCC_PERIPHCLK_I2S3;
PeriphClkInit->I2s3ClockSelection = RCC_I2S3CLKSOURCE_SYSCLK;
#endif /* STM32F103xE || STM32F103xG */
#if defined(STM32F102x6) || defined(STM32F102xB) || defined(STM32F103x6)\
|| defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG)\
|| defined(STM32F105xC) || defined(STM32F107xC)
/* Get the USB clock configuration -----------------------------------------*/
PeriphClkInit->PeriphClockSelection |= RCC_PERIPHCLK_USB;
PeriphClkInit->UsbClockSelection = __HAL_RCC_GET_USB_SOURCE();
#endif /* STM32F102x6 || STM32F102xB || STM32F103x6 || STM32F103xB || STM32F103xE || STM32F103xG || STM32F105xC || STM32F107xC */
}
/**
* @brief Returns the peripheral clock frequency
* @note Returns 0 if peripheral clock is unknown
* @param PeriphClk Peripheral clock identifier
* This parameter can be one of the following values:
* @arg @ref RCC_PERIPHCLK_RTC RTC peripheral clock
* @arg @ref RCC_PERIPHCLK_ADC ADC peripheral clock
@if STM32F103xE
* @arg @ref RCC_PERIPHCLK_I2S2 I2S2 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S3 I2S3 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S3 I2S3 peripheral clock
@endif
@if STM32F103xG
* @arg @ref RCC_PERIPHCLK_I2S2 I2S2 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S3 I2S3 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S3 I2S3 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S2 I2S2 peripheral clock
@endif
@if STM32F105xC
* @arg @ref RCC_PERIPHCLK_I2S2 I2S2 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S3 I2S3 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S3 I2S3 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S2 I2S2 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S3 I2S3 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S3 I2S3 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S2 I2S2 peripheral clock
* @arg @ref RCC_PERIPHCLK_USB USB peripheral clock
@endif
@if STM32F107xC
* @arg @ref RCC_PERIPHCLK_I2S2 I2S2 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S3 I2S3 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S3 I2S3 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S2 I2S2 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S3 I2S3 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S3 I2S3 peripheral clock
* @arg @ref RCC_PERIPHCLK_I2S2 I2S2 peripheral clock
* @arg @ref RCC_PERIPHCLK_USB USB peripheral clock
@endif
@if STM32F102xx
* @arg @ref RCC_PERIPHCLK_USB USB peripheral clock
@endif
@if STM32F103xx
* @arg @ref RCC_PERIPHCLK_USB USB peripheral clock
@endif
* @retval Frequency in Hz (0: means that no available frequency for the peripheral)
*/
uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk)
{
#if defined(STM32F105xC) || defined(STM32F107xC)
static const uint8_t aPLLMULFactorTable[14U] = {0, 0, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 13};
static const uint8_t aPredivFactorTable[16U] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
uint32_t prediv1 = 0U, pllclk = 0U, pllmul = 0U;
uint32_t pll2mul = 0U, pll3mul = 0U, prediv2 = 0U;
#endif /* STM32F105xC || STM32F107xC */
#if defined(STM32F102x6) || defined(STM32F102xB) || defined(STM32F103x6) || \
defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG)
static const uint8_t aPLLMULFactorTable[16U] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16};
static const uint8_t aPredivFactorTable[2U] = {1, 2};
uint32_t prediv1 = 0U, pllclk = 0U, pllmul = 0U;
#endif /* STM32F102x6 || STM32F102xB || STM32F103x6 || STM32F103xB || STM32F103xE || STM32F103xG */
uint32_t temp_reg = 0U, frequency = 0U;
/* Check the parameters */
assert_param(IS_RCC_PERIPHCLOCK(PeriphClk));
switch (PeriphClk)
{
#if defined(STM32F102x6) || defined(STM32F102xB) || defined(STM32F103x6)\
|| defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG)\
|| defined(STM32F105xC) || defined(STM32F107xC)
case RCC_PERIPHCLK_USB:
{
/* Get RCC configuration ------------------------------------------------------*/
temp_reg = RCC->CFGR;
/* Check if PLL is enabled */
if (HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLLON))
{
pllmul = aPLLMULFactorTable[(uint32_t)(temp_reg & RCC_CFGR_PLLMULL) >> RCC_CFGR_PLLMULL_Pos];
if ((temp_reg & RCC_CFGR_PLLSRC) != RCC_PLLSOURCE_HSI_DIV2)
{
#if defined(STM32F105xC) || defined(STM32F107xC) || defined(STM32F100xB)\
|| defined(STM32F100xE)
prediv1 = aPredivFactorTable[(uint32_t)(RCC->CFGR2 & RCC_CFGR2_PREDIV1) >> RCC_CFGR2_PREDIV1_Pos];
#else
prediv1 = aPredivFactorTable[(uint32_t)(RCC->CFGR & RCC_CFGR_PLLXTPRE) >> RCC_CFGR_PLLXTPRE_Pos];
#endif /* STM32F105xC || STM32F107xC || STM32F100xB || STM32F100xE */
#if defined(STM32F105xC) || defined(STM32F107xC)
if (HAL_IS_BIT_SET(RCC->CFGR2, RCC_CFGR2_PREDIV1SRC))
{
/* PLL2 selected as Prediv1 source */
/* PLLCLK = PLL2CLK / PREDIV1 * PLLMUL with PLL2CLK = HSE/PREDIV2 * PLL2MUL */
prediv2 = ((RCC->CFGR2 & RCC_CFGR2_PREDIV2) >> RCC_CFGR2_PREDIV2_Pos) + 1;
pll2mul = ((RCC->CFGR2 & RCC_CFGR2_PLL2MUL) >> RCC_CFGR2_PLL2MUL_Pos) + 2;
pllclk = (uint32_t)((((HSE_VALUE / prediv2) * pll2mul) / prediv1) * pllmul);
}
else
{
/* HSE used as PLL clock source : PLLCLK = HSE/PREDIV1 * PLLMUL */
pllclk = (uint32_t)((HSE_VALUE / prediv1) * pllmul);
}
/* If PLLMUL was set to 13 means that it was to cover the case PLLMUL 6.5 (avoid using float) */
/* In this case need to divide pllclk by 2 */
if (pllmul == aPLLMULFactorTable[(uint32_t)(RCC_CFGR_PLLMULL6_5) >> RCC_CFGR_PLLMULL_Pos])
{
pllclk = pllclk / 2;
}
#else
if ((temp_reg & RCC_CFGR_PLLSRC) != RCC_PLLSOURCE_HSI_DIV2)
{
/* HSE used as PLL clock source : PLLCLK = HSE/PREDIV1 * PLLMUL */
pllclk = (uint32_t)((HSE_VALUE / prediv1) * pllmul);
}
#endif /* STM32F105xC || STM32F107xC */
}
else
{
/* HSI used as PLL clock source : PLLCLK = HSI/2 * PLLMUL */
pllclk = (uint32_t)((HSI_VALUE >> 1) * pllmul);
}
/* Calcul of the USB frequency*/
#if defined(STM32F105xC) || defined(STM32F107xC)
/* USBCLK = PLLVCO = (2 x PLLCLK) / USB prescaler */
if (__HAL_RCC_GET_USB_SOURCE() == RCC_USBCLKSOURCE_PLL_DIV2)
{
/* Prescaler of 2 selected for USB */
frequency = pllclk;
}
else
{
/* Prescaler of 3 selected for USB */
frequency = (2 * pllclk) / 3;
}
#else
/* USBCLK = PLLCLK / USB prescaler */
if (__HAL_RCC_GET_USB_SOURCE() == RCC_USBCLKSOURCE_PLL)
{
/* No prescaler selected for USB */
frequency = pllclk;
}
else
{
/* Prescaler of 1.5 selected for USB */
frequency = (pllclk * 2) / 3;
}
#endif
}
break;
}
#endif /* STM32F102x6 || STM32F102xB || STM32F103x6 || STM32F103xB || STM32F103xE || STM32F103xG || STM32F105xC || STM32F107xC */
#if defined(STM32F103xE) || defined(STM32F103xG) || defined(STM32F105xC) || defined(STM32F107xC)
case RCC_PERIPHCLK_I2S2:
{
#if defined(STM32F103xE) || defined(STM32F103xG)
/* SYSCLK used as source clock for I2S2 */
frequency = HAL_RCC_GetSysClockFreq();
#else
if (__HAL_RCC_GET_I2S2_SOURCE() == RCC_I2S2CLKSOURCE_SYSCLK)
{
/* SYSCLK used as source clock for I2S2 */
frequency = HAL_RCC_GetSysClockFreq();
}
else
{
/* Check if PLLI2S is enabled */
if (HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLL3ON))
{
/* PLLI2SVCO = 2 * PLLI2SCLK = 2 * (HSE/PREDIV2 * PLL3MUL) */
prediv2 = ((RCC->CFGR2 & RCC_CFGR2_PREDIV2) >> RCC_CFGR2_PREDIV2_Pos) + 1;
pll3mul = ((RCC->CFGR2 & RCC_CFGR2_PLL3MUL) >> RCC_CFGR2_PLL3MUL_Pos) + 2;
frequency = (uint32_t)(2 * ((HSE_VALUE / prediv2) * pll3mul));
}
}
#endif /* STM32F103xE || STM32F103xG */
break;
}
case RCC_PERIPHCLK_I2S3:
{
#if defined(STM32F103xE) || defined(STM32F103xG)
/* SYSCLK used as source clock for I2S3 */
frequency = HAL_RCC_GetSysClockFreq();
#else
if (__HAL_RCC_GET_I2S3_SOURCE() == RCC_I2S3CLKSOURCE_SYSCLK)
{
/* SYSCLK used as source clock for I2S3 */
frequency = HAL_RCC_GetSysClockFreq();
}
else
{
/* Check if PLLI2S is enabled */
if (HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLL3ON))
{
/* PLLI2SVCO = 2 * PLLI2SCLK = 2 * (HSE/PREDIV2 * PLL3MUL) */
prediv2 = ((RCC->CFGR2 & RCC_CFGR2_PREDIV2) >> RCC_CFGR2_PREDIV2_Pos) + 1;
pll3mul = ((RCC->CFGR2 & RCC_CFGR2_PLL3MUL) >> RCC_CFGR2_PLL3MUL_Pos) + 2;
frequency = (uint32_t)(2 * ((HSE_VALUE / prediv2) * pll3mul));
}
}
#endif /* STM32F103xE || STM32F103xG */
break;
}
#endif /* STM32F103xE || STM32F103xG || STM32F105xC || STM32F107xC */
case RCC_PERIPHCLK_RTC:
{
/* Get RCC BDCR configuration ------------------------------------------------------*/
temp_reg = RCC->BDCR;
/* Check if LSE is ready if RTC clock selection is LSE */
if (((temp_reg & RCC_BDCR_RTCSEL) == RCC_RTCCLKSOURCE_LSE) && (HAL_IS_BIT_SET(temp_reg, RCC_BDCR_LSERDY)))
{
frequency = LSE_VALUE;
}
/* Check if LSI is ready if RTC clock selection is LSI */
else if (((temp_reg & RCC_BDCR_RTCSEL) == RCC_RTCCLKSOURCE_LSI) && (HAL_IS_BIT_SET(RCC->CSR, RCC_CSR_LSIRDY)))
{
frequency = LSI_VALUE;
}
else if (((temp_reg & RCC_BDCR_RTCSEL) == RCC_RTCCLKSOURCE_HSE_DIV128) && (HAL_IS_BIT_SET(RCC->CR, RCC_CR_HSERDY)))
{
frequency = HSE_VALUE / 128U;
}
/* Clock not enabled for RTC*/
else
{
/* nothing to do: frequency already initialized to 0U */
}
break;
}
case RCC_PERIPHCLK_ADC:
{
frequency = HAL_RCC_GetPCLK2Freq() / (((__HAL_RCC_GET_ADC_SOURCE() >> RCC_CFGR_ADCPRE_Pos) + 1) * 2);
break;
}
default:
{
break;
}
}
return (frequency);
}
/**
* @}
*/
#if defined(STM32F105xC) || defined(STM32F107xC)
/** @defgroup RCCEx_Exported_Functions_Group2 PLLI2S Management function
* @brief PLLI2S Management functions
*
@verbatim
===============================================================================
##### Extended PLLI2S Management functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to control the PLLI2S
activation or deactivation
@endverbatim
* @{
*/
/**
* @brief Enable PLLI2S
* @param PLLI2SInit pointer to an RCC_PLLI2SInitTypeDef structure that
* contains the configuration information for the PLLI2S
* @note The PLLI2S configuration not modified if used by I2S2 or I2S3 Interface.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_RCCEx_EnablePLLI2S(RCC_PLLI2SInitTypeDef *PLLI2SInit)
{
uint32_t tickstart = 0U;
/* Check that PLL I2S has not been already enabled by I2S2 or I2S3*/
if (HAL_IS_BIT_CLR(RCC->CFGR2, RCC_CFGR2_I2S2SRC) && HAL_IS_BIT_CLR(RCC->CFGR2, RCC_CFGR2_I2S3SRC))
{
/* Check the parameters */
assert_param(IS_RCC_PLLI2S_MUL(PLLI2SInit->PLLI2SMUL));
assert_param(IS_RCC_HSE_PREDIV2(PLLI2SInit->HSEPrediv2Value));
/* Prediv2 can be written only when the PLL2 is disabled. */
/* Return an error only if new value is different from the programmed value */
if (HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLL2ON) && \
(__HAL_RCC_HSE_GET_PREDIV2() != PLLI2SInit->HSEPrediv2Value))
{
return HAL_ERROR;
}
/* Disable the main PLLI2S. */
__HAL_RCC_PLLI2S_DISABLE();
/* Get Start Tick*/
tickstart = HAL_GetTick();
/* Wait till PLLI2S is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* Configure the HSE prediv2 factor --------------------------------*/
__HAL_RCC_HSE_PREDIV2_CONFIG(PLLI2SInit->HSEPrediv2Value);
/* Configure the main PLLI2S multiplication factors. */
__HAL_RCC_PLLI2S_CONFIG(PLLI2SInit->PLLI2SMUL);
/* Enable the main PLLI2S. */
__HAL_RCC_PLLI2S_ENABLE();
/* Get Start Tick*/
tickstart = HAL_GetTick();
/* Wait till PLLI2S is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
else
{
/* PLLI2S cannot be modified as already used by I2S2 or I2S3 */
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Disable PLLI2S
* @note PLLI2S is not disabled if used by I2S2 or I2S3 Interface.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_RCCEx_DisablePLLI2S(void)
{
uint32_t tickstart = 0U;
/* Disable PLL I2S as not requested by I2S2 or I2S3*/
if (HAL_IS_BIT_CLR(RCC->CFGR2, RCC_CFGR2_I2S2SRC) && HAL_IS_BIT_CLR(RCC->CFGR2, RCC_CFGR2_I2S3SRC))
{
/* Disable the main PLLI2S. */
__HAL_RCC_PLLI2S_DISABLE();
/* Get Start Tick*/
tickstart = HAL_GetTick();
/* Wait till PLLI2S is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLLI2S_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
else
{
/* PLLI2S is currently used by I2S2 or I2S3. Cannot be disabled.*/
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @}
*/
/** @defgroup RCCEx_Exported_Functions_Group3 PLL2 Management function
* @brief PLL2 Management functions
*
@verbatim
===============================================================================
##### Extended PLL2 Management functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to control the PLL2
activation or deactivation
@endverbatim
* @{
*/
/**
* @brief Enable PLL2
* @param PLL2Init pointer to an RCC_PLL2InitTypeDef structure that
* contains the configuration information for the PLL2
* @note The PLL2 configuration not modified if used indirectly as system clock.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_RCCEx_EnablePLL2(RCC_PLL2InitTypeDef *PLL2Init)
{
uint32_t tickstart = 0U;
/* This bit can not be cleared if the PLL2 clock is used indirectly as system
clock (i.e. it is used as PLL clock entry that is used as system clock). */
if ((__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSE) && \
(__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_PLLCLK) && \
((READ_BIT(RCC->CFGR2, RCC_CFGR2_PREDIV1SRC)) == RCC_CFGR2_PREDIV1SRC_PLL2))
{
return HAL_ERROR;
}
else
{
/* Check the parameters */
assert_param(IS_RCC_PLL2_MUL(PLL2Init->PLL2MUL));
assert_param(IS_RCC_HSE_PREDIV2(PLL2Init->HSEPrediv2Value));
/* Prediv2 can be written only when the PLLI2S is disabled. */
/* Return an error only if new value is different from the programmed value */
if (HAL_IS_BIT_SET(RCC->CR, RCC_CR_PLL3ON) && \
(__HAL_RCC_HSE_GET_PREDIV2() != PLL2Init->HSEPrediv2Value))
{
return HAL_ERROR;
}
/* Disable the main PLL2. */
__HAL_RCC_PLL2_DISABLE();
/* Get Start Tick*/
tickstart = HAL_GetTick();
/* Wait till PLL2 is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLL2RDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLL2_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
/* Configure the HSE prediv2 factor --------------------------------*/
__HAL_RCC_HSE_PREDIV2_CONFIG(PLL2Init->HSEPrediv2Value);
/* Configure the main PLL2 multiplication factors. */
__HAL_RCC_PLL2_CONFIG(PLL2Init->PLL2MUL);
/* Enable the main PLL2. */
__HAL_RCC_PLL2_ENABLE();
/* Get Start Tick*/
tickstart = HAL_GetTick();
/* Wait till PLL2 is ready */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLL2RDY) == RESET)
{
if ((HAL_GetTick() - tickstart) > PLL2_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
return HAL_OK;
}
/**
* @brief Disable PLL2
* @note PLL2 is not disabled if used indirectly as system clock.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_RCCEx_DisablePLL2(void)
{
uint32_t tickstart = 0U;
/* This bit can not be cleared if the PLL2 clock is used indirectly as system
clock (i.e. it is used as PLL clock entry that is used as system clock). */
if ((__HAL_RCC_GET_PLL_OSCSOURCE() == RCC_PLLSOURCE_HSE) && \
(__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_PLLCLK) && \
((READ_BIT(RCC->CFGR2, RCC_CFGR2_PREDIV1SRC)) == RCC_CFGR2_PREDIV1SRC_PLL2))
{
return HAL_ERROR;
}
else
{
/* Disable the main PLL2. */
__HAL_RCC_PLL2_DISABLE();
/* Get Start Tick*/
tickstart = HAL_GetTick();
/* Wait till PLL2 is disabled */
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLL2RDY) != RESET)
{
if ((HAL_GetTick() - tickstart) > PLL2_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
}
}
return HAL_OK;
}
/**
* @}
*/
#endif /* STM32F105xC || STM32F107xC */
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_RCC_MODULE_ENABLED */
/**
* @}
*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2359 @@
/**
******************************************************************************
* @file stm32f1xx_hal_tim_ex.c
* @author MCD Application Team
* @brief TIM HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the Timer Extended peripheral:
* + Time Hall Sensor Interface Initialization
* + Time Hall Sensor Interface Start
* + Time Complementary signal break and dead time configuration
* + Time Master and Slave synchronization configuration
* + Timer remapping capabilities configuration
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### TIMER Extended features #####
==============================================================================
[..]
The Timer Extended features include:
(#) Complementary outputs with programmable dead-time for :
(++) Output Compare
(++) PWM generation (Edge and Center-aligned Mode)
(++) One-pulse mode output
(#) Synchronization circuit to control the timer with external signals and to
interconnect several timers together.
(#) Break input to put the timer output signals in reset state or in a known state.
(#) Supports incremental (quadrature) encoder and hall-sensor circuitry for
positioning purposes
##### How to use this driver #####
==============================================================================
[..]
(#) Initialize the TIM low level resources by implementing the following functions
depending on the selected feature:
(++) Hall Sensor output : HAL_TIMEx_HallSensor_MspInit()
(#) Initialize the TIM low level resources :
(##) Enable the TIM interface clock using __HAL_RCC_TIMx_CLK_ENABLE();
(##) TIM pins configuration
(+++) Enable the clock for the TIM GPIOs using the following function:
__HAL_RCC_GPIOx_CLK_ENABLE();
(+++) Configure these TIM pins in Alternate function mode using HAL_GPIO_Init();
(#) The external Clock can be configured, if needed (the default clock is the
internal clock from the APBx), using the following function:
HAL_TIM_ConfigClockSource, the clock configuration should be done before
any start function.
(#) Configure the TIM in the desired functioning mode using one of the
initialization function of this driver:
(++) HAL_TIMEx_HallSensor_Init() and HAL_TIMEx_ConfigCommutEvent(): to use the
Timer Hall Sensor Interface and the commutation event with the corresponding
Interrupt and DMA request if needed (Note that One Timer is used to interface
with the Hall sensor Interface and another Timer should be used to use
the commutation event).
(#) Activate the TIM peripheral using one of the start functions:
(++) Complementary Output Compare : HAL_TIMEx_OCN_Start(), HAL_TIMEx_OCN_Start_DMA(),
HAL_TIMEx_OCN_Start_IT()
(++) Complementary PWM generation : HAL_TIMEx_PWMN_Start(), HAL_TIMEx_PWMN_Start_DMA(),
HAL_TIMEx_PWMN_Start_IT()
(++) Complementary One-pulse mode output : HAL_TIMEx_OnePulseN_Start(), HAL_TIMEx_OnePulseN_Start_IT()
(++) Hall Sensor output : HAL_TIMEx_HallSensor_Start(), HAL_TIMEx_HallSensor_Start_DMA(),
HAL_TIMEx_HallSensor_Start_IT().
@endverbatim
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup TIMEx TIMEx
* @brief TIM Extended HAL module driver
* @{
*/
#ifdef HAL_TIM_MODULE_ENABLED
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static void TIM_DMADelayPulseNCplt(DMA_HandleTypeDef *hdma);
static void TIM_DMAErrorCCxN(DMA_HandleTypeDef *hdma);
static void TIM_CCxNChannelCmd(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ChannelNState);
/* Exported functions --------------------------------------------------------*/
/** @defgroup TIMEx_Exported_Functions TIM Extended Exported Functions
* @{
*/
/** @defgroup TIMEx_Exported_Functions_Group1 Extended Timer Hall Sensor functions
* @brief Timer Hall Sensor functions
*
@verbatim
==============================================================================
##### Timer Hall Sensor functions #####
==============================================================================
[..]
This section provides functions allowing to:
(+) Initialize and configure TIM HAL Sensor.
(+) De-initialize TIM HAL Sensor.
(+) Start the Hall Sensor Interface.
(+) Stop the Hall Sensor Interface.
(+) Start the Hall Sensor Interface and enable interrupts.
(+) Stop the Hall Sensor Interface and disable interrupts.
(+) Start the Hall Sensor Interface and enable DMA transfers.
(+) Stop the Hall Sensor Interface and disable DMA transfers.
@endverbatim
* @{
*/
/**
* @brief Initializes the TIM Hall Sensor Interface and initialize the associated handle.
* @note When the timer instance is initialized in Hall Sensor Interface mode,
* timer channels 1 and channel 2 are reserved and cannot be used for
* other purpose.
* @param htim TIM Hall Sensor Interface handle
* @param sConfig TIM Hall Sensor configuration structure
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_HallSensor_Init(TIM_HandleTypeDef *htim, const TIM_HallSensor_InitTypeDef *sConfig)
{
TIM_OC_InitTypeDef OC_Config;
/* Check the TIM handle allocation */
if (htim == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_TIM_HALL_SENSOR_INTERFACE_INSTANCE(htim->Instance));
assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode));
assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision));
assert_param(IS_TIM_AUTORELOAD_PRELOAD(htim->Init.AutoReloadPreload));
assert_param(IS_TIM_IC_POLARITY(sConfig->IC1Polarity));
assert_param(IS_TIM_PERIOD(htim->Init.Period));
assert_param(IS_TIM_IC_PRESCALER(sConfig->IC1Prescaler));
assert_param(IS_TIM_IC_FILTER(sConfig->IC1Filter));
if (htim->State == HAL_TIM_STATE_RESET)
{
/* Allocate lock resource and initialize it */
htim->Lock = HAL_UNLOCKED;
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
/* Reset interrupt callbacks to legacy week callbacks */
TIM_ResetCallback(htim);
if (htim->HallSensor_MspInitCallback == NULL)
{
htim->HallSensor_MspInitCallback = HAL_TIMEx_HallSensor_MspInit;
}
/* Init the low level hardware : GPIO, CLOCK, NVIC */
htim->HallSensor_MspInitCallback(htim);
#else
/* Init the low level hardware : GPIO, CLOCK, NVIC and DMA */
HAL_TIMEx_HallSensor_MspInit(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
/* Set the TIM state */
htim->State = HAL_TIM_STATE_BUSY;
/* Configure the Time base in the Encoder Mode */
TIM_Base_SetConfig(htim->Instance, &htim->Init);
/* Configure the Channel 1 as Input Channel to interface with the three Outputs of the Hall sensor */
TIM_TI1_SetConfig(htim->Instance, sConfig->IC1Polarity, TIM_ICSELECTION_TRC, sConfig->IC1Filter);
/* Reset the IC1PSC Bits */
htim->Instance->CCMR1 &= ~TIM_CCMR1_IC1PSC;
/* Set the IC1PSC value */
htim->Instance->CCMR1 |= sConfig->IC1Prescaler;
/* Enable the Hall sensor interface (XOR function of the three inputs) */
htim->Instance->CR2 |= TIM_CR2_TI1S;
/* Select the TIM_TS_TI1F_ED signal as Input trigger for the TIM */
htim->Instance->SMCR &= ~TIM_SMCR_TS;
htim->Instance->SMCR |= TIM_TS_TI1F_ED;
/* Use the TIM_TS_TI1F_ED signal to reset the TIM counter each edge detection */
htim->Instance->SMCR &= ~TIM_SMCR_SMS;
htim->Instance->SMCR |= TIM_SLAVEMODE_RESET;
/* Program channel 2 in PWM 2 mode with the desired Commutation_Delay*/
OC_Config.OCFastMode = TIM_OCFAST_DISABLE;
OC_Config.OCIdleState = TIM_OCIDLESTATE_RESET;
OC_Config.OCMode = TIM_OCMODE_PWM2;
OC_Config.OCNIdleState = TIM_OCNIDLESTATE_RESET;
OC_Config.OCNPolarity = TIM_OCNPOLARITY_HIGH;
OC_Config.OCPolarity = TIM_OCPOLARITY_HIGH;
OC_Config.Pulse = sConfig->Commutation_Delay;
TIM_OC2_SetConfig(htim->Instance, &OC_Config);
/* Select OC2REF as trigger output on TRGO: write the MMS bits in the TIMx_CR2
register to 101 */
htim->Instance->CR2 &= ~TIM_CR2_MMS;
htim->Instance->CR2 |= TIM_TRGO_OC2REF;
/* Initialize the DMA burst operation state */
htim->DMABurstState = HAL_DMA_BURST_STATE_READY;
/* Initialize the TIM channels state */
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_READY);
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_READY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_READY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_READY);
/* Initialize the TIM state*/
htim->State = HAL_TIM_STATE_READY;
return HAL_OK;
}
/**
* @brief DeInitializes the TIM Hall Sensor interface
* @param htim TIM Hall Sensor Interface handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_HallSensor_DeInit(TIM_HandleTypeDef *htim)
{
/* Check the parameters */
assert_param(IS_TIM_INSTANCE(htim->Instance));
htim->State = HAL_TIM_STATE_BUSY;
/* Disable the TIM Peripheral Clock */
__HAL_TIM_DISABLE(htim);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
if (htim->HallSensor_MspDeInitCallback == NULL)
{
htim->HallSensor_MspDeInitCallback = HAL_TIMEx_HallSensor_MspDeInit;
}
/* DeInit the low level hardware */
htim->HallSensor_MspDeInitCallback(htim);
#else
/* DeInit the low level hardware: GPIO, CLOCK, NVIC */
HAL_TIMEx_HallSensor_MspDeInit(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
/* Change the DMA burst operation state */
htim->DMABurstState = HAL_DMA_BURST_STATE_RESET;
/* Change the TIM channels state */
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_RESET);
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_RESET);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_RESET);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_RESET);
/* Change TIM state */
htim->State = HAL_TIM_STATE_RESET;
/* Release Lock */
__HAL_UNLOCK(htim);
return HAL_OK;
}
/**
* @brief Initializes the TIM Hall Sensor MSP.
* @param htim TIM Hall Sensor Interface handle
* @retval None
*/
__weak void HAL_TIMEx_HallSensor_MspInit(TIM_HandleTypeDef *htim)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(htim);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_TIMEx_HallSensor_MspInit could be implemented in the user file
*/
}
/**
* @brief DeInitializes TIM Hall Sensor MSP.
* @param htim TIM Hall Sensor Interface handle
* @retval None
*/
__weak void HAL_TIMEx_HallSensor_MspDeInit(TIM_HandleTypeDef *htim)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(htim);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_TIMEx_HallSensor_MspDeInit could be implemented in the user file
*/
}
/**
* @brief Starts the TIM Hall Sensor Interface.
* @param htim TIM Hall Sensor Interface handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_HallSensor_Start(TIM_HandleTypeDef *htim)
{
uint32_t tmpsmcr;
HAL_TIM_ChannelStateTypeDef channel_1_state = TIM_CHANNEL_STATE_GET(htim, TIM_CHANNEL_1);
HAL_TIM_ChannelStateTypeDef channel_2_state = TIM_CHANNEL_STATE_GET(htim, TIM_CHANNEL_2);
HAL_TIM_ChannelStateTypeDef complementary_channel_1_state = TIM_CHANNEL_N_STATE_GET(htim, TIM_CHANNEL_1);
HAL_TIM_ChannelStateTypeDef complementary_channel_2_state = TIM_CHANNEL_N_STATE_GET(htim, TIM_CHANNEL_2);
/* Check the parameters */
assert_param(IS_TIM_HALL_SENSOR_INTERFACE_INSTANCE(htim->Instance));
/* Check the TIM channels state */
if ((channel_1_state != HAL_TIM_CHANNEL_STATE_READY)
|| (channel_2_state != HAL_TIM_CHANNEL_STATE_READY)
|| (complementary_channel_1_state != HAL_TIM_CHANNEL_STATE_READY)
|| (complementary_channel_2_state != HAL_TIM_CHANNEL_STATE_READY))
{
return HAL_ERROR;
}
/* Set the TIM channels state */
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_BUSY);
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_BUSY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_BUSY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_BUSY);
/* Enable the Input Capture channel 1
(in the Hall Sensor Interface the three possible channels that can be used are TIM_CHANNEL_1,
TIM_CHANNEL_2 and TIM_CHANNEL_3) */
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);
/* Enable the Peripheral, except in trigger mode where enable is automatically done with trigger */
if (IS_TIM_SLAVE_INSTANCE(htim->Instance))
{
tmpsmcr = htim->Instance->SMCR & TIM_SMCR_SMS;
if (!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr))
{
__HAL_TIM_ENABLE(htim);
}
}
else
{
__HAL_TIM_ENABLE(htim);
}
/* Return function status */
return HAL_OK;
}
/**
* @brief Stops the TIM Hall sensor Interface.
* @param htim TIM Hall Sensor Interface handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_HallSensor_Stop(TIM_HandleTypeDef *htim)
{
/* Check the parameters */
assert_param(IS_TIM_HALL_SENSOR_INTERFACE_INSTANCE(htim->Instance));
/* Disable the Input Capture channels 1, 2 and 3
(in the Hall Sensor Interface the three possible channels that can be used are TIM_CHANNEL_1,
TIM_CHANNEL_2 and TIM_CHANNEL_3) */
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_DISABLE);
/* Disable the Peripheral */
__HAL_TIM_DISABLE(htim);
/* Set the TIM channels state */
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_READY);
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_READY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_READY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_READY);
/* Return function status */
return HAL_OK;
}
/**
* @brief Starts the TIM Hall Sensor Interface in interrupt mode.
* @param htim TIM Hall Sensor Interface handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_HallSensor_Start_IT(TIM_HandleTypeDef *htim)
{
uint32_t tmpsmcr;
HAL_TIM_ChannelStateTypeDef channel_1_state = TIM_CHANNEL_STATE_GET(htim, TIM_CHANNEL_1);
HAL_TIM_ChannelStateTypeDef channel_2_state = TIM_CHANNEL_STATE_GET(htim, TIM_CHANNEL_2);
HAL_TIM_ChannelStateTypeDef complementary_channel_1_state = TIM_CHANNEL_N_STATE_GET(htim, TIM_CHANNEL_1);
HAL_TIM_ChannelStateTypeDef complementary_channel_2_state = TIM_CHANNEL_N_STATE_GET(htim, TIM_CHANNEL_2);
/* Check the parameters */
assert_param(IS_TIM_HALL_SENSOR_INTERFACE_INSTANCE(htim->Instance));
/* Check the TIM channels state */
if ((channel_1_state != HAL_TIM_CHANNEL_STATE_READY)
|| (channel_2_state != HAL_TIM_CHANNEL_STATE_READY)
|| (complementary_channel_1_state != HAL_TIM_CHANNEL_STATE_READY)
|| (complementary_channel_2_state != HAL_TIM_CHANNEL_STATE_READY))
{
return HAL_ERROR;
}
/* Set the TIM channels state */
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_BUSY);
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_BUSY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_BUSY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_BUSY);
/* Enable the capture compare Interrupts 1 event */
__HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1);
/* Enable the Input Capture channel 1
(in the Hall Sensor Interface the three possible channels that can be used are TIM_CHANNEL_1,
TIM_CHANNEL_2 and TIM_CHANNEL_3) */
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);
/* Enable the Peripheral, except in trigger mode where enable is automatically done with trigger */
if (IS_TIM_SLAVE_INSTANCE(htim->Instance))
{
tmpsmcr = htim->Instance->SMCR & TIM_SMCR_SMS;
if (!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr))
{
__HAL_TIM_ENABLE(htim);
}
}
else
{
__HAL_TIM_ENABLE(htim);
}
/* Return function status */
return HAL_OK;
}
/**
* @brief Stops the TIM Hall Sensor Interface in interrupt mode.
* @param htim TIM Hall Sensor Interface handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_HallSensor_Stop_IT(TIM_HandleTypeDef *htim)
{
/* Check the parameters */
assert_param(IS_TIM_HALL_SENSOR_INTERFACE_INSTANCE(htim->Instance));
/* Disable the Input Capture channel 1
(in the Hall Sensor Interface the three possible channels that can be used are TIM_CHANNEL_1,
TIM_CHANNEL_2 and TIM_CHANNEL_3) */
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_DISABLE);
/* Disable the capture compare Interrupts event */
__HAL_TIM_DISABLE_IT(htim, TIM_IT_CC1);
/* Disable the Peripheral */
__HAL_TIM_DISABLE(htim);
/* Set the TIM channels state */
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_READY);
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_READY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_READY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_READY);
/* Return function status */
return HAL_OK;
}
/**
* @brief Starts the TIM Hall Sensor Interface in DMA mode.
* @param htim TIM Hall Sensor Interface handle
* @param pData The destination Buffer address.
* @param Length The length of data to be transferred from TIM peripheral to memory.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_HallSensor_Start_DMA(TIM_HandleTypeDef *htim, uint32_t *pData, uint16_t Length)
{
uint32_t tmpsmcr;
HAL_TIM_ChannelStateTypeDef channel_1_state = TIM_CHANNEL_STATE_GET(htim, TIM_CHANNEL_1);
HAL_TIM_ChannelStateTypeDef complementary_channel_1_state = TIM_CHANNEL_N_STATE_GET(htim, TIM_CHANNEL_1);
/* Check the parameters */
assert_param(IS_TIM_HALL_SENSOR_INTERFACE_INSTANCE(htim->Instance));
/* Set the TIM channel state */
if ((channel_1_state == HAL_TIM_CHANNEL_STATE_BUSY)
|| (complementary_channel_1_state == HAL_TIM_CHANNEL_STATE_BUSY))
{
return HAL_BUSY;
}
else if ((channel_1_state == HAL_TIM_CHANNEL_STATE_READY)
&& (complementary_channel_1_state == HAL_TIM_CHANNEL_STATE_READY))
{
if ((pData == NULL) || (Length == 0U))
{
return HAL_ERROR;
}
else
{
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_BUSY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_BUSY);
}
}
else
{
return HAL_ERROR;
}
/* Enable the Input Capture channel 1
(in the Hall Sensor Interface the three possible channels that can be used are TIM_CHANNEL_1,
TIM_CHANNEL_2 and TIM_CHANNEL_3) */
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);
/* Set the DMA Input Capture 1 Callbacks */
htim->hdma[TIM_DMA_ID_CC1]->XferCpltCallback = TIM_DMACaptureCplt;
htim->hdma[TIM_DMA_ID_CC1]->XferHalfCpltCallback = TIM_DMACaptureHalfCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_CC1]->XferErrorCallback = TIM_DMAError ;
/* Enable the DMA channel for Capture 1*/
if (HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC1], (uint32_t)&htim->Instance->CCR1, (uint32_t)pData, Length) != HAL_OK)
{
/* Return error status */
return HAL_ERROR;
}
/* Enable the capture compare 1 Interrupt */
__HAL_TIM_ENABLE_DMA(htim, TIM_DMA_CC1);
/* Enable the Peripheral, except in trigger mode where enable is automatically done with trigger */
if (IS_TIM_SLAVE_INSTANCE(htim->Instance))
{
tmpsmcr = htim->Instance->SMCR & TIM_SMCR_SMS;
if (!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr))
{
__HAL_TIM_ENABLE(htim);
}
}
else
{
__HAL_TIM_ENABLE(htim);
}
/* Return function status */
return HAL_OK;
}
/**
* @brief Stops the TIM Hall Sensor Interface in DMA mode.
* @param htim TIM Hall Sensor Interface handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_HallSensor_Stop_DMA(TIM_HandleTypeDef *htim)
{
/* Check the parameters */
assert_param(IS_TIM_HALL_SENSOR_INTERFACE_INSTANCE(htim->Instance));
/* Disable the Input Capture channel 1
(in the Hall Sensor Interface the three possible channels that can be used are TIM_CHANNEL_1,
TIM_CHANNEL_2 and TIM_CHANNEL_3) */
TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_DISABLE);
/* Disable the capture compare Interrupts 1 event */
__HAL_TIM_DISABLE_DMA(htim, TIM_DMA_CC1);
(void)HAL_DMA_Abort_IT(htim->hdma[TIM_DMA_ID_CC1]);
/* Disable the Peripheral */
__HAL_TIM_DISABLE(htim);
/* Set the TIM channel state */
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_READY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_READY);
/* Return function status */
return HAL_OK;
}
/**
* @}
*/
/** @defgroup TIMEx_Exported_Functions_Group2 Extended Timer Complementary Output Compare functions
* @brief Timer Complementary Output Compare functions
*
@verbatim
==============================================================================
##### Timer Complementary Output Compare functions #####
==============================================================================
[..]
This section provides functions allowing to:
(+) Start the Complementary Output Compare/PWM.
(+) Stop the Complementary Output Compare/PWM.
(+) Start the Complementary Output Compare/PWM and enable interrupts.
(+) Stop the Complementary Output Compare/PWM and disable interrupts.
(+) Start the Complementary Output Compare/PWM and enable DMA transfers.
(+) Stop the Complementary Output Compare/PWM and disable DMA transfers.
@endverbatim
* @{
*/
/**
* @brief Starts the TIM Output Compare signal generation on the complementary
* output.
* @param htim TIM Output Compare handle
* @param Channel TIM Channel to be enabled
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @arg TIM_CHANNEL_3: TIM Channel 3 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_OCN_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
{
uint32_t tmpsmcr;
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, Channel));
/* Check the TIM complementary channel state */
if (TIM_CHANNEL_N_STATE_GET(htim, Channel) != HAL_TIM_CHANNEL_STATE_READY)
{
return HAL_ERROR;
}
/* Set the TIM complementary channel state */
TIM_CHANNEL_N_STATE_SET(htim, Channel, HAL_TIM_CHANNEL_STATE_BUSY);
/* Enable the Capture compare channel N */
TIM_CCxNChannelCmd(htim->Instance, Channel, TIM_CCxN_ENABLE);
/* Enable the Main Output */
__HAL_TIM_MOE_ENABLE(htim);
/* Enable the Peripheral, except in trigger mode where enable is automatically done with trigger */
if (IS_TIM_SLAVE_INSTANCE(htim->Instance))
{
tmpsmcr = htim->Instance->SMCR & TIM_SMCR_SMS;
if (!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr))
{
__HAL_TIM_ENABLE(htim);
}
}
else
{
__HAL_TIM_ENABLE(htim);
}
/* Return function status */
return HAL_OK;
}
/**
* @brief Stops the TIM Output Compare signal generation on the complementary
* output.
* @param htim TIM handle
* @param Channel TIM Channel to be disabled
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @arg TIM_CHANNEL_3: TIM Channel 3 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_OCN_Stop(TIM_HandleTypeDef *htim, uint32_t Channel)
{
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, Channel));
/* Disable the Capture compare channel N */
TIM_CCxNChannelCmd(htim->Instance, Channel, TIM_CCxN_DISABLE);
/* Disable the Main Output */
__HAL_TIM_MOE_DISABLE(htim);
/* Disable the Peripheral */
__HAL_TIM_DISABLE(htim);
/* Set the TIM complementary channel state */
TIM_CHANNEL_N_STATE_SET(htim, Channel, HAL_TIM_CHANNEL_STATE_READY);
/* Return function status */
return HAL_OK;
}
/**
* @brief Starts the TIM Output Compare signal generation in interrupt mode
* on the complementary output.
* @param htim TIM OC handle
* @param Channel TIM Channel to be enabled
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @arg TIM_CHANNEL_3: TIM Channel 3 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_OCN_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel)
{
HAL_StatusTypeDef status = HAL_OK;
uint32_t tmpsmcr;
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, Channel));
/* Check the TIM complementary channel state */
if (TIM_CHANNEL_N_STATE_GET(htim, Channel) != HAL_TIM_CHANNEL_STATE_READY)
{
return HAL_ERROR;
}
/* Set the TIM complementary channel state */
TIM_CHANNEL_N_STATE_SET(htim, Channel, HAL_TIM_CHANNEL_STATE_BUSY);
switch (Channel)
{
case TIM_CHANNEL_1:
{
/* Enable the TIM Output Compare interrupt */
__HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1);
break;
}
case TIM_CHANNEL_2:
{
/* Enable the TIM Output Compare interrupt */
__HAL_TIM_ENABLE_IT(htim, TIM_IT_CC2);
break;
}
case TIM_CHANNEL_3:
{
/* Enable the TIM Output Compare interrupt */
__HAL_TIM_ENABLE_IT(htim, TIM_IT_CC3);
break;
}
default:
status = HAL_ERROR;
break;
}
if (status == HAL_OK)
{
/* Enable the TIM Break interrupt */
__HAL_TIM_ENABLE_IT(htim, TIM_IT_BREAK);
/* Enable the Capture compare channel N */
TIM_CCxNChannelCmd(htim->Instance, Channel, TIM_CCxN_ENABLE);
/* Enable the Main Output */
__HAL_TIM_MOE_ENABLE(htim);
/* Enable the Peripheral, except in trigger mode where enable is automatically done with trigger */
if (IS_TIM_SLAVE_INSTANCE(htim->Instance))
{
tmpsmcr = htim->Instance->SMCR & TIM_SMCR_SMS;
if (!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr))
{
__HAL_TIM_ENABLE(htim);
}
}
else
{
__HAL_TIM_ENABLE(htim);
}
}
/* Return function status */
return status;
}
/**
* @brief Stops the TIM Output Compare signal generation in interrupt mode
* on the complementary output.
* @param htim TIM Output Compare handle
* @param Channel TIM Channel to be disabled
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @arg TIM_CHANNEL_3: TIM Channel 3 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_OCN_Stop_IT(TIM_HandleTypeDef *htim, uint32_t Channel)
{
HAL_StatusTypeDef status = HAL_OK;
uint32_t tmpccer;
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, Channel));
switch (Channel)
{
case TIM_CHANNEL_1:
{
/* Disable the TIM Output Compare interrupt */
__HAL_TIM_DISABLE_IT(htim, TIM_IT_CC1);
break;
}
case TIM_CHANNEL_2:
{
/* Disable the TIM Output Compare interrupt */
__HAL_TIM_DISABLE_IT(htim, TIM_IT_CC2);
break;
}
case TIM_CHANNEL_3:
{
/* Disable the TIM Output Compare interrupt */
__HAL_TIM_DISABLE_IT(htim, TIM_IT_CC3);
break;
}
default:
status = HAL_ERROR;
break;
}
if (status == HAL_OK)
{
/* Disable the Capture compare channel N */
TIM_CCxNChannelCmd(htim->Instance, Channel, TIM_CCxN_DISABLE);
/* Disable the TIM Break interrupt (only if no more channel is active) */
tmpccer = htim->Instance->CCER;
if ((tmpccer & TIM_CCER_CCxNE_MASK) == (uint32_t)RESET)
{
__HAL_TIM_DISABLE_IT(htim, TIM_IT_BREAK);
}
/* Disable the Main Output */
__HAL_TIM_MOE_DISABLE(htim);
/* Disable the Peripheral */
__HAL_TIM_DISABLE(htim);
/* Set the TIM complementary channel state */
TIM_CHANNEL_N_STATE_SET(htim, Channel, HAL_TIM_CHANNEL_STATE_READY);
}
/* Return function status */
return status;
}
/**
* @brief Starts the TIM Output Compare signal generation in DMA mode
* on the complementary output.
* @param htim TIM Output Compare handle
* @param Channel TIM Channel to be enabled
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @arg TIM_CHANNEL_3: TIM Channel 3 selected
* @param pData The source Buffer address.
* @param Length The length of data to be transferred from memory to TIM peripheral
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_OCN_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, const uint32_t *pData,
uint16_t Length)
{
HAL_StatusTypeDef status = HAL_OK;
uint32_t tmpsmcr;
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, Channel));
/* Set the TIM complementary channel state */
if (TIM_CHANNEL_N_STATE_GET(htim, Channel) == HAL_TIM_CHANNEL_STATE_BUSY)
{
return HAL_BUSY;
}
else if (TIM_CHANNEL_N_STATE_GET(htim, Channel) == HAL_TIM_CHANNEL_STATE_READY)
{
if ((pData == NULL) || (Length == 0U))
{
return HAL_ERROR;
}
else
{
TIM_CHANNEL_N_STATE_SET(htim, Channel, HAL_TIM_CHANNEL_STATE_BUSY);
}
}
else
{
return HAL_ERROR;
}
switch (Channel)
{
case TIM_CHANNEL_1:
{
/* Set the DMA compare callbacks */
htim->hdma[TIM_DMA_ID_CC1]->XferCpltCallback = TIM_DMADelayPulseNCplt;
htim->hdma[TIM_DMA_ID_CC1]->XferHalfCpltCallback = TIM_DMADelayPulseHalfCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_CC1]->XferErrorCallback = TIM_DMAErrorCCxN ;
/* Enable the DMA channel */
if (HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC1], (uint32_t)pData, (uint32_t)&htim->Instance->CCR1,
Length) != HAL_OK)
{
/* Return error status */
return HAL_ERROR;
}
/* Enable the TIM Output Compare DMA request */
__HAL_TIM_ENABLE_DMA(htim, TIM_DMA_CC1);
break;
}
case TIM_CHANNEL_2:
{
/* Set the DMA compare callbacks */
htim->hdma[TIM_DMA_ID_CC2]->XferCpltCallback = TIM_DMADelayPulseNCplt;
htim->hdma[TIM_DMA_ID_CC2]->XferHalfCpltCallback = TIM_DMADelayPulseHalfCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_CC2]->XferErrorCallback = TIM_DMAErrorCCxN ;
/* Enable the DMA channel */
if (HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC2], (uint32_t)pData, (uint32_t)&htim->Instance->CCR2,
Length) != HAL_OK)
{
/* Return error status */
return HAL_ERROR;
}
/* Enable the TIM Output Compare DMA request */
__HAL_TIM_ENABLE_DMA(htim, TIM_DMA_CC2);
break;
}
case TIM_CHANNEL_3:
{
/* Set the DMA compare callbacks */
htim->hdma[TIM_DMA_ID_CC3]->XferCpltCallback = TIM_DMADelayPulseNCplt;
htim->hdma[TIM_DMA_ID_CC3]->XferHalfCpltCallback = TIM_DMADelayPulseHalfCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_CC3]->XferErrorCallback = TIM_DMAErrorCCxN ;
/* Enable the DMA channel */
if (HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC3], (uint32_t)pData, (uint32_t)&htim->Instance->CCR3,
Length) != HAL_OK)
{
/* Return error status */
return HAL_ERROR;
}
/* Enable the TIM Output Compare DMA request */
__HAL_TIM_ENABLE_DMA(htim, TIM_DMA_CC3);
break;
}
default:
status = HAL_ERROR;
break;
}
if (status == HAL_OK)
{
/* Enable the Capture compare channel N */
TIM_CCxNChannelCmd(htim->Instance, Channel, TIM_CCxN_ENABLE);
/* Enable the Main Output */
__HAL_TIM_MOE_ENABLE(htim);
/* Enable the Peripheral, except in trigger mode where enable is automatically done with trigger */
if (IS_TIM_SLAVE_INSTANCE(htim->Instance))
{
tmpsmcr = htim->Instance->SMCR & TIM_SMCR_SMS;
if (!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr))
{
__HAL_TIM_ENABLE(htim);
}
}
else
{
__HAL_TIM_ENABLE(htim);
}
}
/* Return function status */
return status;
}
/**
* @brief Stops the TIM Output Compare signal generation in DMA mode
* on the complementary output.
* @param htim TIM Output Compare handle
* @param Channel TIM Channel to be disabled
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @arg TIM_CHANNEL_3: TIM Channel 3 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_OCN_Stop_DMA(TIM_HandleTypeDef *htim, uint32_t Channel)
{
HAL_StatusTypeDef status = HAL_OK;
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, Channel));
switch (Channel)
{
case TIM_CHANNEL_1:
{
/* Disable the TIM Output Compare DMA request */
__HAL_TIM_DISABLE_DMA(htim, TIM_DMA_CC1);
(void)HAL_DMA_Abort_IT(htim->hdma[TIM_DMA_ID_CC1]);
break;
}
case TIM_CHANNEL_2:
{
/* Disable the TIM Output Compare DMA request */
__HAL_TIM_DISABLE_DMA(htim, TIM_DMA_CC2);
(void)HAL_DMA_Abort_IT(htim->hdma[TIM_DMA_ID_CC2]);
break;
}
case TIM_CHANNEL_3:
{
/* Disable the TIM Output Compare DMA request */
__HAL_TIM_DISABLE_DMA(htim, TIM_DMA_CC3);
(void)HAL_DMA_Abort_IT(htim->hdma[TIM_DMA_ID_CC3]);
break;
}
default:
status = HAL_ERROR;
break;
}
if (status == HAL_OK)
{
/* Disable the Capture compare channel N */
TIM_CCxNChannelCmd(htim->Instance, Channel, TIM_CCxN_DISABLE);
/* Disable the Main Output */
__HAL_TIM_MOE_DISABLE(htim);
/* Disable the Peripheral */
__HAL_TIM_DISABLE(htim);
/* Set the TIM complementary channel state */
TIM_CHANNEL_N_STATE_SET(htim, Channel, HAL_TIM_CHANNEL_STATE_READY);
}
/* Return function status */
return status;
}
/**
* @}
*/
/** @defgroup TIMEx_Exported_Functions_Group3 Extended Timer Complementary PWM functions
* @brief Timer Complementary PWM functions
*
@verbatim
==============================================================================
##### Timer Complementary PWM functions #####
==============================================================================
[..]
This section provides functions allowing to:
(+) Start the Complementary PWM.
(+) Stop the Complementary PWM.
(+) Start the Complementary PWM and enable interrupts.
(+) Stop the Complementary PWM and disable interrupts.
(+) Start the Complementary PWM and enable DMA transfers.
(+) Stop the Complementary PWM and disable DMA transfers.
@endverbatim
* @{
*/
/**
* @brief Starts the PWM signal generation on the complementary output.
* @param htim TIM handle
* @param Channel TIM Channel to be enabled
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @arg TIM_CHANNEL_3: TIM Channel 3 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_PWMN_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
{
uint32_t tmpsmcr;
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, Channel));
/* Check the TIM complementary channel state */
if (TIM_CHANNEL_N_STATE_GET(htim, Channel) != HAL_TIM_CHANNEL_STATE_READY)
{
return HAL_ERROR;
}
/* Set the TIM complementary channel state */
TIM_CHANNEL_N_STATE_SET(htim, Channel, HAL_TIM_CHANNEL_STATE_BUSY);
/* Enable the complementary PWM output */
TIM_CCxNChannelCmd(htim->Instance, Channel, TIM_CCxN_ENABLE);
/* Enable the Main Output */
__HAL_TIM_MOE_ENABLE(htim);
/* Enable the Peripheral, except in trigger mode where enable is automatically done with trigger */
if (IS_TIM_SLAVE_INSTANCE(htim->Instance))
{
tmpsmcr = htim->Instance->SMCR & TIM_SMCR_SMS;
if (!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr))
{
__HAL_TIM_ENABLE(htim);
}
}
else
{
__HAL_TIM_ENABLE(htim);
}
/* Return function status */
return HAL_OK;
}
/**
* @brief Stops the PWM signal generation on the complementary output.
* @param htim TIM handle
* @param Channel TIM Channel to be disabled
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @arg TIM_CHANNEL_3: TIM Channel 3 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_PWMN_Stop(TIM_HandleTypeDef *htim, uint32_t Channel)
{
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, Channel));
/* Disable the complementary PWM output */
TIM_CCxNChannelCmd(htim->Instance, Channel, TIM_CCxN_DISABLE);
/* Disable the Main Output */
__HAL_TIM_MOE_DISABLE(htim);
/* Disable the Peripheral */
__HAL_TIM_DISABLE(htim);
/* Set the TIM complementary channel state */
TIM_CHANNEL_N_STATE_SET(htim, Channel, HAL_TIM_CHANNEL_STATE_READY);
/* Return function status */
return HAL_OK;
}
/**
* @brief Starts the PWM signal generation in interrupt mode on the
* complementary output.
* @param htim TIM handle
* @param Channel TIM Channel to be disabled
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @arg TIM_CHANNEL_3: TIM Channel 3 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_PWMN_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel)
{
HAL_StatusTypeDef status = HAL_OK;
uint32_t tmpsmcr;
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, Channel));
/* Check the TIM complementary channel state */
if (TIM_CHANNEL_N_STATE_GET(htim, Channel) != HAL_TIM_CHANNEL_STATE_READY)
{
return HAL_ERROR;
}
/* Set the TIM complementary channel state */
TIM_CHANNEL_N_STATE_SET(htim, Channel, HAL_TIM_CHANNEL_STATE_BUSY);
switch (Channel)
{
case TIM_CHANNEL_1:
{
/* Enable the TIM Capture/Compare 1 interrupt */
__HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1);
break;
}
case TIM_CHANNEL_2:
{
/* Enable the TIM Capture/Compare 2 interrupt */
__HAL_TIM_ENABLE_IT(htim, TIM_IT_CC2);
break;
}
case TIM_CHANNEL_3:
{
/* Enable the TIM Capture/Compare 3 interrupt */
__HAL_TIM_ENABLE_IT(htim, TIM_IT_CC3);
break;
}
default:
status = HAL_ERROR;
break;
}
if (status == HAL_OK)
{
/* Enable the TIM Break interrupt */
__HAL_TIM_ENABLE_IT(htim, TIM_IT_BREAK);
/* Enable the complementary PWM output */
TIM_CCxNChannelCmd(htim->Instance, Channel, TIM_CCxN_ENABLE);
/* Enable the Main Output */
__HAL_TIM_MOE_ENABLE(htim);
/* Enable the Peripheral, except in trigger mode where enable is automatically done with trigger */
if (IS_TIM_SLAVE_INSTANCE(htim->Instance))
{
tmpsmcr = htim->Instance->SMCR & TIM_SMCR_SMS;
if (!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr))
{
__HAL_TIM_ENABLE(htim);
}
}
else
{
__HAL_TIM_ENABLE(htim);
}
}
/* Return function status */
return status;
}
/**
* @brief Stops the PWM signal generation in interrupt mode on the
* complementary output.
* @param htim TIM handle
* @param Channel TIM Channel to be disabled
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @arg TIM_CHANNEL_3: TIM Channel 3 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_PWMN_Stop_IT(TIM_HandleTypeDef *htim, uint32_t Channel)
{
HAL_StatusTypeDef status = HAL_OK;
uint32_t tmpccer;
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, Channel));
switch (Channel)
{
case TIM_CHANNEL_1:
{
/* Disable the TIM Capture/Compare 1 interrupt */
__HAL_TIM_DISABLE_IT(htim, TIM_IT_CC1);
break;
}
case TIM_CHANNEL_2:
{
/* Disable the TIM Capture/Compare 2 interrupt */
__HAL_TIM_DISABLE_IT(htim, TIM_IT_CC2);
break;
}
case TIM_CHANNEL_3:
{
/* Disable the TIM Capture/Compare 3 interrupt */
__HAL_TIM_DISABLE_IT(htim, TIM_IT_CC3);
break;
}
default:
status = HAL_ERROR;
break;
}
if (status == HAL_OK)
{
/* Disable the complementary PWM output */
TIM_CCxNChannelCmd(htim->Instance, Channel, TIM_CCxN_DISABLE);
/* Disable the TIM Break interrupt (only if no more channel is active) */
tmpccer = htim->Instance->CCER;
if ((tmpccer & TIM_CCER_CCxNE_MASK) == (uint32_t)RESET)
{
__HAL_TIM_DISABLE_IT(htim, TIM_IT_BREAK);
}
/* Disable the Main Output */
__HAL_TIM_MOE_DISABLE(htim);
/* Disable the Peripheral */
__HAL_TIM_DISABLE(htim);
/* Set the TIM complementary channel state */
TIM_CHANNEL_N_STATE_SET(htim, Channel, HAL_TIM_CHANNEL_STATE_READY);
}
/* Return function status */
return status;
}
/**
* @brief Starts the TIM PWM signal generation in DMA mode on the
* complementary output
* @param htim TIM handle
* @param Channel TIM Channel to be enabled
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @arg TIM_CHANNEL_3: TIM Channel 3 selected
* @param pData The source Buffer address.
* @param Length The length of data to be transferred from memory to TIM peripheral
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_PWMN_Start_DMA(TIM_HandleTypeDef *htim, uint32_t Channel, const uint32_t *pData,
uint16_t Length)
{
HAL_StatusTypeDef status = HAL_OK;
uint32_t tmpsmcr;
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, Channel));
/* Set the TIM complementary channel state */
if (TIM_CHANNEL_N_STATE_GET(htim, Channel) == HAL_TIM_CHANNEL_STATE_BUSY)
{
return HAL_BUSY;
}
else if (TIM_CHANNEL_N_STATE_GET(htim, Channel) == HAL_TIM_CHANNEL_STATE_READY)
{
if ((pData == NULL) || (Length == 0U))
{
return HAL_ERROR;
}
else
{
TIM_CHANNEL_N_STATE_SET(htim, Channel, HAL_TIM_CHANNEL_STATE_BUSY);
}
}
else
{
return HAL_ERROR;
}
switch (Channel)
{
case TIM_CHANNEL_1:
{
/* Set the DMA compare callbacks */
htim->hdma[TIM_DMA_ID_CC1]->XferCpltCallback = TIM_DMADelayPulseNCplt;
htim->hdma[TIM_DMA_ID_CC1]->XferHalfCpltCallback = TIM_DMADelayPulseHalfCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_CC1]->XferErrorCallback = TIM_DMAErrorCCxN ;
/* Enable the DMA channel */
if (HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC1], (uint32_t)pData, (uint32_t)&htim->Instance->CCR1,
Length) != HAL_OK)
{
/* Return error status */
return HAL_ERROR;
}
/* Enable the TIM Capture/Compare 1 DMA request */
__HAL_TIM_ENABLE_DMA(htim, TIM_DMA_CC1);
break;
}
case TIM_CHANNEL_2:
{
/* Set the DMA compare callbacks */
htim->hdma[TIM_DMA_ID_CC2]->XferCpltCallback = TIM_DMADelayPulseNCplt;
htim->hdma[TIM_DMA_ID_CC2]->XferHalfCpltCallback = TIM_DMADelayPulseHalfCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_CC2]->XferErrorCallback = TIM_DMAErrorCCxN ;
/* Enable the DMA channel */
if (HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC2], (uint32_t)pData, (uint32_t)&htim->Instance->CCR2,
Length) != HAL_OK)
{
/* Return error status */
return HAL_ERROR;
}
/* Enable the TIM Capture/Compare 2 DMA request */
__HAL_TIM_ENABLE_DMA(htim, TIM_DMA_CC2);
break;
}
case TIM_CHANNEL_3:
{
/* Set the DMA compare callbacks */
htim->hdma[TIM_DMA_ID_CC3]->XferCpltCallback = TIM_DMADelayPulseNCplt;
htim->hdma[TIM_DMA_ID_CC3]->XferHalfCpltCallback = TIM_DMADelayPulseHalfCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_CC3]->XferErrorCallback = TIM_DMAErrorCCxN ;
/* Enable the DMA channel */
if (HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC3], (uint32_t)pData, (uint32_t)&htim->Instance->CCR3,
Length) != HAL_OK)
{
/* Return error status */
return HAL_ERROR;
}
/* Enable the TIM Capture/Compare 3 DMA request */
__HAL_TIM_ENABLE_DMA(htim, TIM_DMA_CC3);
break;
}
default:
status = HAL_ERROR;
break;
}
if (status == HAL_OK)
{
/* Enable the complementary PWM output */
TIM_CCxNChannelCmd(htim->Instance, Channel, TIM_CCxN_ENABLE);
/* Enable the Main Output */
__HAL_TIM_MOE_ENABLE(htim);
/* Enable the Peripheral, except in trigger mode where enable is automatically done with trigger */
if (IS_TIM_SLAVE_INSTANCE(htim->Instance))
{
tmpsmcr = htim->Instance->SMCR & TIM_SMCR_SMS;
if (!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr))
{
__HAL_TIM_ENABLE(htim);
}
}
else
{
__HAL_TIM_ENABLE(htim);
}
}
/* Return function status */
return status;
}
/**
* @brief Stops the TIM PWM signal generation in DMA mode on the complementary
* output
* @param htim TIM handle
* @param Channel TIM Channel to be disabled
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @arg TIM_CHANNEL_3: TIM Channel 3 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_PWMN_Stop_DMA(TIM_HandleTypeDef *htim, uint32_t Channel)
{
HAL_StatusTypeDef status = HAL_OK;
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, Channel));
switch (Channel)
{
case TIM_CHANNEL_1:
{
/* Disable the TIM Capture/Compare 1 DMA request */
__HAL_TIM_DISABLE_DMA(htim, TIM_DMA_CC1);
(void)HAL_DMA_Abort_IT(htim->hdma[TIM_DMA_ID_CC1]);
break;
}
case TIM_CHANNEL_2:
{
/* Disable the TIM Capture/Compare 2 DMA request */
__HAL_TIM_DISABLE_DMA(htim, TIM_DMA_CC2);
(void)HAL_DMA_Abort_IT(htim->hdma[TIM_DMA_ID_CC2]);
break;
}
case TIM_CHANNEL_3:
{
/* Disable the TIM Capture/Compare 3 DMA request */
__HAL_TIM_DISABLE_DMA(htim, TIM_DMA_CC3);
(void)HAL_DMA_Abort_IT(htim->hdma[TIM_DMA_ID_CC3]);
break;
}
default:
status = HAL_ERROR;
break;
}
if (status == HAL_OK)
{
/* Disable the complementary PWM output */
TIM_CCxNChannelCmd(htim->Instance, Channel, TIM_CCxN_DISABLE);
/* Disable the Main Output */
__HAL_TIM_MOE_DISABLE(htim);
/* Disable the Peripheral */
__HAL_TIM_DISABLE(htim);
/* Set the TIM complementary channel state */
TIM_CHANNEL_N_STATE_SET(htim, Channel, HAL_TIM_CHANNEL_STATE_READY);
}
/* Return function status */
return status;
}
/**
* @}
*/
/** @defgroup TIMEx_Exported_Functions_Group4 Extended Timer Complementary One Pulse functions
* @brief Timer Complementary One Pulse functions
*
@verbatim
==============================================================================
##### Timer Complementary One Pulse functions #####
==============================================================================
[..]
This section provides functions allowing to:
(+) Start the Complementary One Pulse generation.
(+) Stop the Complementary One Pulse.
(+) Start the Complementary One Pulse and enable interrupts.
(+) Stop the Complementary One Pulse and disable interrupts.
@endverbatim
* @{
*/
/**
* @brief Starts the TIM One Pulse signal generation on the complementary
* output.
* @note OutputChannel must match the pulse output channel chosen when calling
* @ref HAL_TIM_OnePulse_ConfigChannel().
* @param htim TIM One Pulse handle
* @param OutputChannel pulse output channel to enable
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_OnePulseN_Start(TIM_HandleTypeDef *htim, uint32_t OutputChannel)
{
uint32_t input_channel = (OutputChannel == TIM_CHANNEL_1) ? TIM_CHANNEL_2 : TIM_CHANNEL_1;
HAL_TIM_ChannelStateTypeDef channel_1_state = TIM_CHANNEL_STATE_GET(htim, TIM_CHANNEL_1);
HAL_TIM_ChannelStateTypeDef channel_2_state = TIM_CHANNEL_STATE_GET(htim, TIM_CHANNEL_2);
HAL_TIM_ChannelStateTypeDef complementary_channel_1_state = TIM_CHANNEL_N_STATE_GET(htim, TIM_CHANNEL_1);
HAL_TIM_ChannelStateTypeDef complementary_channel_2_state = TIM_CHANNEL_N_STATE_GET(htim, TIM_CHANNEL_2);
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, OutputChannel));
/* Check the TIM channels state */
if ((channel_1_state != HAL_TIM_CHANNEL_STATE_READY)
|| (channel_2_state != HAL_TIM_CHANNEL_STATE_READY)
|| (complementary_channel_1_state != HAL_TIM_CHANNEL_STATE_READY)
|| (complementary_channel_2_state != HAL_TIM_CHANNEL_STATE_READY))
{
return HAL_ERROR;
}
/* Set the TIM channels state */
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_BUSY);
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_BUSY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_BUSY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_BUSY);
/* Enable the complementary One Pulse output channel and the Input Capture channel */
TIM_CCxNChannelCmd(htim->Instance, OutputChannel, TIM_CCxN_ENABLE);
TIM_CCxChannelCmd(htim->Instance, input_channel, TIM_CCx_ENABLE);
/* Enable the Main Output */
__HAL_TIM_MOE_ENABLE(htim);
/* Return function status */
return HAL_OK;
}
/**
* @brief Stops the TIM One Pulse signal generation on the complementary
* output.
* @note OutputChannel must match the pulse output channel chosen when calling
* @ref HAL_TIM_OnePulse_ConfigChannel().
* @param htim TIM One Pulse handle
* @param OutputChannel pulse output channel to disable
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_OnePulseN_Stop(TIM_HandleTypeDef *htim, uint32_t OutputChannel)
{
uint32_t input_channel = (OutputChannel == TIM_CHANNEL_1) ? TIM_CHANNEL_2 : TIM_CHANNEL_1;
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, OutputChannel));
/* Disable the complementary One Pulse output channel and the Input Capture channel */
TIM_CCxNChannelCmd(htim->Instance, OutputChannel, TIM_CCxN_DISABLE);
TIM_CCxChannelCmd(htim->Instance, input_channel, TIM_CCx_DISABLE);
/* Disable the Main Output */
__HAL_TIM_MOE_DISABLE(htim);
/* Disable the Peripheral */
__HAL_TIM_DISABLE(htim);
/* Set the TIM channels state */
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_READY);
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_READY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_READY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_READY);
/* Return function status */
return HAL_OK;
}
/**
* @brief Starts the TIM One Pulse signal generation in interrupt mode on the
* complementary channel.
* @note OutputChannel must match the pulse output channel chosen when calling
* @ref HAL_TIM_OnePulse_ConfigChannel().
* @param htim TIM One Pulse handle
* @param OutputChannel pulse output channel to enable
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_OnePulseN_Start_IT(TIM_HandleTypeDef *htim, uint32_t OutputChannel)
{
uint32_t input_channel = (OutputChannel == TIM_CHANNEL_1) ? TIM_CHANNEL_2 : TIM_CHANNEL_1;
HAL_TIM_ChannelStateTypeDef channel_1_state = TIM_CHANNEL_STATE_GET(htim, TIM_CHANNEL_1);
HAL_TIM_ChannelStateTypeDef channel_2_state = TIM_CHANNEL_STATE_GET(htim, TIM_CHANNEL_2);
HAL_TIM_ChannelStateTypeDef complementary_channel_1_state = TIM_CHANNEL_N_STATE_GET(htim, TIM_CHANNEL_1);
HAL_TIM_ChannelStateTypeDef complementary_channel_2_state = TIM_CHANNEL_N_STATE_GET(htim, TIM_CHANNEL_2);
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, OutputChannel));
/* Check the TIM channels state */
if ((channel_1_state != HAL_TIM_CHANNEL_STATE_READY)
|| (channel_2_state != HAL_TIM_CHANNEL_STATE_READY)
|| (complementary_channel_1_state != HAL_TIM_CHANNEL_STATE_READY)
|| (complementary_channel_2_state != HAL_TIM_CHANNEL_STATE_READY))
{
return HAL_ERROR;
}
/* Set the TIM channels state */
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_BUSY);
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_BUSY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_BUSY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_BUSY);
/* Enable the TIM Capture/Compare 1 interrupt */
__HAL_TIM_ENABLE_IT(htim, TIM_IT_CC1);
/* Enable the TIM Capture/Compare 2 interrupt */
__HAL_TIM_ENABLE_IT(htim, TIM_IT_CC2);
/* Enable the complementary One Pulse output channel and the Input Capture channel */
TIM_CCxNChannelCmd(htim->Instance, OutputChannel, TIM_CCxN_ENABLE);
TIM_CCxChannelCmd(htim->Instance, input_channel, TIM_CCx_ENABLE);
/* Enable the Main Output */
__HAL_TIM_MOE_ENABLE(htim);
/* Return function status */
return HAL_OK;
}
/**
* @brief Stops the TIM One Pulse signal generation in interrupt mode on the
* complementary channel.
* @note OutputChannel must match the pulse output channel chosen when calling
* @ref HAL_TIM_OnePulse_ConfigChannel().
* @param htim TIM One Pulse handle
* @param OutputChannel pulse output channel to disable
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1 selected
* @arg TIM_CHANNEL_2: TIM Channel 2 selected
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_OnePulseN_Stop_IT(TIM_HandleTypeDef *htim, uint32_t OutputChannel)
{
uint32_t input_channel = (OutputChannel == TIM_CHANNEL_1) ? TIM_CHANNEL_2 : TIM_CHANNEL_1;
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, OutputChannel));
/* Disable the TIM Capture/Compare 1 interrupt */
__HAL_TIM_DISABLE_IT(htim, TIM_IT_CC1);
/* Disable the TIM Capture/Compare 2 interrupt */
__HAL_TIM_DISABLE_IT(htim, TIM_IT_CC2);
/* Disable the complementary One Pulse output channel and the Input Capture channel */
TIM_CCxNChannelCmd(htim->Instance, OutputChannel, TIM_CCxN_DISABLE);
TIM_CCxChannelCmd(htim->Instance, input_channel, TIM_CCx_DISABLE);
/* Disable the Main Output */
__HAL_TIM_MOE_DISABLE(htim);
/* Disable the Peripheral */
__HAL_TIM_DISABLE(htim);
/* Set the TIM channels state */
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_READY);
TIM_CHANNEL_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_READY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_READY);
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_READY);
/* Return function status */
return HAL_OK;
}
/**
* @}
*/
/** @defgroup TIMEx_Exported_Functions_Group5 Extended Peripheral Control functions
* @brief Peripheral Control functions
*
@verbatim
==============================================================================
##### Peripheral Control functions #####
==============================================================================
[..]
This section provides functions allowing to:
(+) Configure the commutation event in case of use of the Hall sensor interface.
(+) Configure Output channels for OC and PWM mode.
(+) Configure Complementary channels, break features and dead time.
(+) Configure Master synchronization.
(+) Configure timer remapping capabilities.
@endverbatim
* @{
*/
/**
* @brief Configure the TIM commutation event sequence.
* @note This function is mandatory to use the commutation event in order to
* update the configuration at each commutation detection on the TRGI input of the Timer,
* the typical use of this feature is with the use of another Timer(interface Timer)
* configured in Hall sensor interface, this interface Timer will generate the
* commutation at its TRGO output (connected to Timer used in this function) each time
* the TI1 of the Interface Timer detect a commutation at its input TI1.
* @param htim TIM handle
* @param InputTrigger the Internal trigger corresponding to the Timer Interfacing with the Hall sensor
* This parameter can be one of the following values:
* @arg TIM_TS_ITR0: Internal trigger 0 selected
* @arg TIM_TS_ITR1: Internal trigger 1 selected
* @arg TIM_TS_ITR2: Internal trigger 2 selected
* @arg TIM_TS_ITR3: Internal trigger 3 selected
* @arg TIM_TS_NONE: No trigger is needed
* @param CommutationSource the Commutation Event source
* This parameter can be one of the following values:
* @arg TIM_COMMUTATION_TRGI: Commutation source is the TRGI of the Interface Timer
* @arg TIM_COMMUTATION_SOFTWARE: Commutation source is set by software using the COMG bit
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_ConfigCommutEvent(TIM_HandleTypeDef *htim, uint32_t InputTrigger,
uint32_t CommutationSource)
{
/* Check the parameters */
assert_param(IS_TIM_COMMUTATION_EVENT_INSTANCE(htim->Instance));
assert_param(IS_TIM_INTERNAL_TRIGGEREVENT_SELECTION(InputTrigger));
__HAL_LOCK(htim);
if ((InputTrigger == TIM_TS_ITR0) || (InputTrigger == TIM_TS_ITR1) ||
(InputTrigger == TIM_TS_ITR2) || (InputTrigger == TIM_TS_ITR3))
{
/* Select the Input trigger */
htim->Instance->SMCR &= ~TIM_SMCR_TS;
htim->Instance->SMCR |= InputTrigger;
}
/* Select the Capture Compare preload feature */
htim->Instance->CR2 |= TIM_CR2_CCPC;
/* Select the Commutation event source */
htim->Instance->CR2 &= ~TIM_CR2_CCUS;
htim->Instance->CR2 |= CommutationSource;
/* Disable Commutation Interrupt */
__HAL_TIM_DISABLE_IT(htim, TIM_IT_COM);
/* Disable Commutation DMA request */
__HAL_TIM_DISABLE_DMA(htim, TIM_DMA_COM);
__HAL_UNLOCK(htim);
return HAL_OK;
}
/**
* @brief Configure the TIM commutation event sequence with interrupt.
* @note This function is mandatory to use the commutation event in order to
* update the configuration at each commutation detection on the TRGI input of the Timer,
* the typical use of this feature is with the use of another Timer(interface Timer)
* configured in Hall sensor interface, this interface Timer will generate the
* commutation at its TRGO output (connected to Timer used in this function) each time
* the TI1 of the Interface Timer detect a commutation at its input TI1.
* @param htim TIM handle
* @param InputTrigger the Internal trigger corresponding to the Timer Interfacing with the Hall sensor
* This parameter can be one of the following values:
* @arg TIM_TS_ITR0: Internal trigger 0 selected
* @arg TIM_TS_ITR1: Internal trigger 1 selected
* @arg TIM_TS_ITR2: Internal trigger 2 selected
* @arg TIM_TS_ITR3: Internal trigger 3 selected
* @arg TIM_TS_NONE: No trigger is needed
* @param CommutationSource the Commutation Event source
* This parameter can be one of the following values:
* @arg TIM_COMMUTATION_TRGI: Commutation source is the TRGI of the Interface Timer
* @arg TIM_COMMUTATION_SOFTWARE: Commutation source is set by software using the COMG bit
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_ConfigCommutEvent_IT(TIM_HandleTypeDef *htim, uint32_t InputTrigger,
uint32_t CommutationSource)
{
/* Check the parameters */
assert_param(IS_TIM_COMMUTATION_EVENT_INSTANCE(htim->Instance));
assert_param(IS_TIM_INTERNAL_TRIGGEREVENT_SELECTION(InputTrigger));
__HAL_LOCK(htim);
if ((InputTrigger == TIM_TS_ITR0) || (InputTrigger == TIM_TS_ITR1) ||
(InputTrigger == TIM_TS_ITR2) || (InputTrigger == TIM_TS_ITR3))
{
/* Select the Input trigger */
htim->Instance->SMCR &= ~TIM_SMCR_TS;
htim->Instance->SMCR |= InputTrigger;
}
/* Select the Capture Compare preload feature */
htim->Instance->CR2 |= TIM_CR2_CCPC;
/* Select the Commutation event source */
htim->Instance->CR2 &= ~TIM_CR2_CCUS;
htim->Instance->CR2 |= CommutationSource;
/* Disable Commutation DMA request */
__HAL_TIM_DISABLE_DMA(htim, TIM_DMA_COM);
/* Enable the Commutation Interrupt */
__HAL_TIM_ENABLE_IT(htim, TIM_IT_COM);
__HAL_UNLOCK(htim);
return HAL_OK;
}
/**
* @brief Configure the TIM commutation event sequence with DMA.
* @note This function is mandatory to use the commutation event in order to
* update the configuration at each commutation detection on the TRGI input of the Timer,
* the typical use of this feature is with the use of another Timer(interface Timer)
* configured in Hall sensor interface, this interface Timer will generate the
* commutation at its TRGO output (connected to Timer used in this function) each time
* the TI1 of the Interface Timer detect a commutation at its input TI1.
* @note The user should configure the DMA in his own software, in This function only the COMDE bit is set
* @param htim TIM handle
* @param InputTrigger the Internal trigger corresponding to the Timer Interfacing with the Hall sensor
* This parameter can be one of the following values:
* @arg TIM_TS_ITR0: Internal trigger 0 selected
* @arg TIM_TS_ITR1: Internal trigger 1 selected
* @arg TIM_TS_ITR2: Internal trigger 2 selected
* @arg TIM_TS_ITR3: Internal trigger 3 selected
* @arg TIM_TS_NONE: No trigger is needed
* @param CommutationSource the Commutation Event source
* This parameter can be one of the following values:
* @arg TIM_COMMUTATION_TRGI: Commutation source is the TRGI of the Interface Timer
* @arg TIM_COMMUTATION_SOFTWARE: Commutation source is set by software using the COMG bit
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_ConfigCommutEvent_DMA(TIM_HandleTypeDef *htim, uint32_t InputTrigger,
uint32_t CommutationSource)
{
/* Check the parameters */
assert_param(IS_TIM_COMMUTATION_EVENT_INSTANCE(htim->Instance));
assert_param(IS_TIM_INTERNAL_TRIGGEREVENT_SELECTION(InputTrigger));
__HAL_LOCK(htim);
if ((InputTrigger == TIM_TS_ITR0) || (InputTrigger == TIM_TS_ITR1) ||
(InputTrigger == TIM_TS_ITR2) || (InputTrigger == TIM_TS_ITR3))
{
/* Select the Input trigger */
htim->Instance->SMCR &= ~TIM_SMCR_TS;
htim->Instance->SMCR |= InputTrigger;
}
/* Select the Capture Compare preload feature */
htim->Instance->CR2 |= TIM_CR2_CCPC;
/* Select the Commutation event source */
htim->Instance->CR2 &= ~TIM_CR2_CCUS;
htim->Instance->CR2 |= CommutationSource;
/* Enable the Commutation DMA Request */
/* Set the DMA Commutation Callback */
htim->hdma[TIM_DMA_ID_COMMUTATION]->XferCpltCallback = TIMEx_DMACommutationCplt;
htim->hdma[TIM_DMA_ID_COMMUTATION]->XferHalfCpltCallback = TIMEx_DMACommutationHalfCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_COMMUTATION]->XferErrorCallback = TIM_DMAError;
/* Disable Commutation Interrupt */
__HAL_TIM_DISABLE_IT(htim, TIM_IT_COM);
/* Enable the Commutation DMA Request */
__HAL_TIM_ENABLE_DMA(htim, TIM_DMA_COM);
__HAL_UNLOCK(htim);
return HAL_OK;
}
/**
* @brief Configures the TIM in master mode.
* @param htim TIM handle.
* @param sMasterConfig pointer to a TIM_MasterConfigTypeDef structure that
* contains the selected trigger output (TRGO) and the Master/Slave
* mode.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_MasterConfigSynchronization(TIM_HandleTypeDef *htim,
const TIM_MasterConfigTypeDef *sMasterConfig)
{
uint32_t tmpcr2;
uint32_t tmpsmcr;
/* Check the parameters */
assert_param(IS_TIM_MASTER_INSTANCE(htim->Instance));
assert_param(IS_TIM_TRGO_SOURCE(sMasterConfig->MasterOutputTrigger));
assert_param(IS_TIM_MSM_STATE(sMasterConfig->MasterSlaveMode));
/* Check input state */
__HAL_LOCK(htim);
/* Change the handler state */
htim->State = HAL_TIM_STATE_BUSY;
/* Get the TIMx CR2 register value */
tmpcr2 = htim->Instance->CR2;
/* Get the TIMx SMCR register value */
tmpsmcr = htim->Instance->SMCR;
/* Reset the MMS Bits */
tmpcr2 &= ~TIM_CR2_MMS;
/* Select the TRGO source */
tmpcr2 |= sMasterConfig->MasterOutputTrigger;
/* Update TIMx CR2 */
htim->Instance->CR2 = tmpcr2;
if (IS_TIM_SLAVE_INSTANCE(htim->Instance))
{
/* Reset the MSM Bit */
tmpsmcr &= ~TIM_SMCR_MSM;
/* Set master mode */
tmpsmcr |= sMasterConfig->MasterSlaveMode;
/* Update TIMx SMCR */
htim->Instance->SMCR = tmpsmcr;
}
/* Change the htim state */
htim->State = HAL_TIM_STATE_READY;
__HAL_UNLOCK(htim);
return HAL_OK;
}
/**
* @brief Configures the Break feature, dead time, Lock level, OSSI/OSSR State
* and the AOE(automatic output enable).
* @param htim TIM handle
* @param sBreakDeadTimeConfig pointer to a TIM_ConfigBreakDeadConfigTypeDef structure that
* contains the BDTR Register configuration information for the TIM peripheral.
* @note Interrupts can be generated when an active level is detected on the
* break input, the break 2 input or the system break input. Break
* interrupt can be enabled by calling the @ref __HAL_TIM_ENABLE_IT macro.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_ConfigBreakDeadTime(TIM_HandleTypeDef *htim,
const TIM_BreakDeadTimeConfigTypeDef *sBreakDeadTimeConfig)
{
/* Keep this variable initialized to 0 as it is used to configure BDTR register */
uint32_t tmpbdtr = 0U;
/* Check the parameters */
assert_param(IS_TIM_BREAK_INSTANCE(htim->Instance));
assert_param(IS_TIM_OSSR_STATE(sBreakDeadTimeConfig->OffStateRunMode));
assert_param(IS_TIM_OSSI_STATE(sBreakDeadTimeConfig->OffStateIDLEMode));
assert_param(IS_TIM_LOCK_LEVEL(sBreakDeadTimeConfig->LockLevel));
assert_param(IS_TIM_DEADTIME(sBreakDeadTimeConfig->DeadTime));
assert_param(IS_TIM_BREAK_STATE(sBreakDeadTimeConfig->BreakState));
assert_param(IS_TIM_BREAK_POLARITY(sBreakDeadTimeConfig->BreakPolarity));
assert_param(IS_TIM_AUTOMATIC_OUTPUT_STATE(sBreakDeadTimeConfig->AutomaticOutput));
/* Check input state */
__HAL_LOCK(htim);
/* Set the Lock level, the Break enable Bit and the Polarity, the OSSR State,
the OSSI State, the dead time value and the Automatic Output Enable Bit */
/* Set the BDTR bits */
MODIFY_REG(tmpbdtr, TIM_BDTR_DTG, sBreakDeadTimeConfig->DeadTime);
MODIFY_REG(tmpbdtr, TIM_BDTR_LOCK, sBreakDeadTimeConfig->LockLevel);
MODIFY_REG(tmpbdtr, TIM_BDTR_OSSI, sBreakDeadTimeConfig->OffStateIDLEMode);
MODIFY_REG(tmpbdtr, TIM_BDTR_OSSR, sBreakDeadTimeConfig->OffStateRunMode);
MODIFY_REG(tmpbdtr, TIM_BDTR_BKE, sBreakDeadTimeConfig->BreakState);
MODIFY_REG(tmpbdtr, TIM_BDTR_BKP, sBreakDeadTimeConfig->BreakPolarity);
MODIFY_REG(tmpbdtr, TIM_BDTR_AOE, sBreakDeadTimeConfig->AutomaticOutput);
/* Set TIMx_BDTR */
htim->Instance->BDTR = tmpbdtr;
__HAL_UNLOCK(htim);
return HAL_OK;
}
/**
* @brief Configures the TIMx Remapping input capabilities.
* @param htim TIM handle.
* @param Remap specifies the TIM remapping source.
*
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIMEx_RemapConfig(TIM_HandleTypeDef *htim, uint32_t Remap)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(htim);
UNUSED(Remap);
return HAL_OK;
}
/**
* @}
*/
/** @defgroup TIMEx_Exported_Functions_Group6 Extended Callbacks functions
* @brief Extended Callbacks functions
*
@verbatim
==============================================================================
##### Extended Callbacks functions #####
==============================================================================
[..]
This section provides Extended TIM callback functions:
(+) Timer Commutation callback
(+) Timer Break callback
@endverbatim
* @{
*/
/**
* @brief Commutation callback in non-blocking mode
* @param htim TIM handle
* @retval None
*/
__weak void HAL_TIMEx_CommutCallback(TIM_HandleTypeDef *htim)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(htim);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_TIMEx_CommutCallback could be implemented in the user file
*/
}
/**
* @brief Commutation half complete callback in non-blocking mode
* @param htim TIM handle
* @retval None
*/
__weak void HAL_TIMEx_CommutHalfCpltCallback(TIM_HandleTypeDef *htim)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(htim);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_TIMEx_CommutHalfCpltCallback could be implemented in the user file
*/
}
/**
* @brief Break detection callback in non-blocking mode
* @param htim TIM handle
* @retval None
*/
__weak void HAL_TIMEx_BreakCallback(TIM_HandleTypeDef *htim)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(htim);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_TIMEx_BreakCallback could be implemented in the user file
*/
}
/**
* @}
*/
/** @defgroup TIMEx_Exported_Functions_Group7 Extended Peripheral State functions
* @brief Extended Peripheral State functions
*
@verbatim
==============================================================================
##### Extended Peripheral State functions #####
==============================================================================
[..]
This subsection permits to get in run-time the status of the peripheral
and the data flow.
@endverbatim
* @{
*/
/**
* @brief Return the TIM Hall Sensor interface handle state.
* @param htim TIM Hall Sensor handle
* @retval HAL state
*/
HAL_TIM_StateTypeDef HAL_TIMEx_HallSensor_GetState(const TIM_HandleTypeDef *htim)
{
return htim->State;
}
/**
* @brief Return actual state of the TIM complementary channel.
* @param htim TIM handle
* @param ChannelN TIM Complementary channel
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1
* @arg TIM_CHANNEL_2: TIM Channel 2
* @arg TIM_CHANNEL_3: TIM Channel 3
* @retval TIM Complementary channel state
*/
HAL_TIM_ChannelStateTypeDef HAL_TIMEx_GetChannelNState(const TIM_HandleTypeDef *htim, uint32_t ChannelN)
{
HAL_TIM_ChannelStateTypeDef channel_state;
/* Check the parameters */
assert_param(IS_TIM_CCXN_INSTANCE(htim->Instance, ChannelN));
channel_state = TIM_CHANNEL_N_STATE_GET(htim, ChannelN);
return channel_state;
}
/**
* @}
*/
/**
* @}
*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup TIMEx_Private_Functions TIM Extended Private Functions
* @{
*/
/**
* @brief TIM DMA Commutation callback.
* @param hdma pointer to DMA handle.
* @retval None
*/
void TIMEx_DMACommutationCplt(DMA_HandleTypeDef *hdma)
{
TIM_HandleTypeDef *htim = (TIM_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* Change the htim state */
htim->State = HAL_TIM_STATE_READY;
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->CommutationCallback(htim);
#else
HAL_TIMEx_CommutCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
/**
* @brief TIM DMA Commutation half complete callback.
* @param hdma pointer to DMA handle.
* @retval None
*/
void TIMEx_DMACommutationHalfCplt(DMA_HandleTypeDef *hdma)
{
TIM_HandleTypeDef *htim = (TIM_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* Change the htim state */
htim->State = HAL_TIM_STATE_READY;
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->CommutationHalfCpltCallback(htim);
#else
HAL_TIMEx_CommutHalfCpltCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
}
/**
* @brief TIM DMA Delay Pulse complete callback (complementary channel).
* @param hdma pointer to DMA handle.
* @retval None
*/
static void TIM_DMADelayPulseNCplt(DMA_HandleTypeDef *hdma)
{
TIM_HandleTypeDef *htim = (TIM_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
if (hdma == htim->hdma[TIM_DMA_ID_CC1])
{
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_1;
if (hdma->Init.Mode == DMA_NORMAL)
{
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_READY);
}
}
else if (hdma == htim->hdma[TIM_DMA_ID_CC2])
{
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_2;
if (hdma->Init.Mode == DMA_NORMAL)
{
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_READY);
}
}
else if (hdma == htim->hdma[TIM_DMA_ID_CC3])
{
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_3;
if (hdma->Init.Mode == DMA_NORMAL)
{
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_3, HAL_TIM_CHANNEL_STATE_READY);
}
}
else
{
/* nothing to do */
}
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->PWM_PulseFinishedCallback(htim);
#else
HAL_TIM_PWM_PulseFinishedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
}
/**
* @brief TIM DMA error callback (complementary channel)
* @param hdma pointer to DMA handle.
* @retval None
*/
static void TIM_DMAErrorCCxN(DMA_HandleTypeDef *hdma)
{
TIM_HandleTypeDef *htim = (TIM_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
if (hdma == htim->hdma[TIM_DMA_ID_CC1])
{
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_1;
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_1, HAL_TIM_CHANNEL_STATE_READY);
}
else if (hdma == htim->hdma[TIM_DMA_ID_CC2])
{
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_2;
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_2, HAL_TIM_CHANNEL_STATE_READY);
}
else if (hdma == htim->hdma[TIM_DMA_ID_CC3])
{
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_3;
TIM_CHANNEL_N_STATE_SET(htim, TIM_CHANNEL_3, HAL_TIM_CHANNEL_STATE_READY);
}
else
{
/* nothing to do */
}
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
htim->ErrorCallback(htim);
#else
HAL_TIM_ErrorCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
}
/**
* @brief Enables or disables the TIM Capture Compare Channel xN.
* @param TIMx to select the TIM peripheral
* @param Channel specifies the TIM Channel
* This parameter can be one of the following values:
* @arg TIM_CHANNEL_1: TIM Channel 1
* @arg TIM_CHANNEL_2: TIM Channel 2
* @arg TIM_CHANNEL_3: TIM Channel 3
* @param ChannelNState specifies the TIM Channel CCxNE bit new state.
* This parameter can be: TIM_CCxN_ENABLE or TIM_CCxN_Disable.
* @retval None
*/
static void TIM_CCxNChannelCmd(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ChannelNState)
{
uint32_t tmp;
tmp = TIM_CCER_CC1NE << (Channel & 0xFU); /* 0xFU = 15 bits max shift */
/* Reset the CCxNE Bit */
TIMx->CCER &= ~tmp;
/* Set or reset the CCxNE Bit */
TIMx->CCER |= (uint32_t)(ChannelNState << (Channel & 0xFU)); /* 0xFU = 15 bits max shift */
}
/**
* @}
*/
#endif /* HAL_TIM_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/

View File

@@ -0,0 +1,3771 @@
/**
******************************************************************************
* @file stm32f1xx_hal_uart.c
* @author MCD Application Team
* @brief UART HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the Universal Asynchronous Receiver Transmitter Peripheral (UART).
* + Initialization and de-initialization functions
* + IO operation functions
* + Peripheral Control functions
* + Peripheral State and Errors functions
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@verbatim
==============================================================================
##### How to use this driver #####
==============================================================================
[..]
The UART HAL driver can be used as follows:
(#) Declare a UART_HandleTypeDef handle structure (eg. UART_HandleTypeDef huart).
(#) Initialize the UART low level resources by implementing the HAL_UART_MspInit() API:
(##) Enable the USARTx interface clock.
(##) UART pins configuration:
(+++) Enable the clock for the UART GPIOs.
(+++) Configure the UART TX/RX pins as alternate function pull-up.
(##) NVIC configuration if you need to use interrupt process (HAL_UART_Transmit_IT()
and HAL_UART_Receive_IT() APIs):
(+++) Configure the USARTx interrupt priority.
(+++) Enable the NVIC USART IRQ handle.
(##) DMA Configuration if you need to use DMA process (HAL_UART_Transmit_DMA()
and HAL_UART_Receive_DMA() APIs):
(+++) Declare a DMA handle structure for the Tx/Rx channel.
(+++) Enable the DMAx interface clock.
(+++) Configure the declared DMA handle structure with the required
Tx/Rx parameters.
(+++) Configure the DMA Tx/Rx channel.
(+++) Associate the initialized DMA handle to the UART DMA Tx/Rx handle.
(+++) Configure the priority and enable the NVIC for the transfer complete
interrupt on the DMA Tx/Rx channel.
(+++) Configure the USARTx interrupt priority and enable the NVIC USART IRQ handle
(used for last byte sending completion detection in DMA non circular mode)
(#) Program the Baud Rate, Word Length, Stop Bit, Parity, Hardware
flow control and Mode(Receiver/Transmitter) in the huart Init structure.
(#) For the UART asynchronous mode, initialize the UART registers by calling
the HAL_UART_Init() API.
(#) For the UART Half duplex mode, initialize the UART registers by calling
the HAL_HalfDuplex_Init() API.
(#) For the LIN mode, initialize the UART registers by calling the HAL_LIN_Init() API.
(#) For the Multi-Processor mode, initialize the UART registers by calling
the HAL_MultiProcessor_Init() API.
[..]
(@) The specific UART interrupts (Transmission complete interrupt,
RXNE interrupt and Error Interrupts) will be managed using the macros
__HAL_UART_ENABLE_IT() and __HAL_UART_DISABLE_IT() inside the transmit
and receive process.
[..]
(@) These APIs (HAL_UART_Init() and HAL_HalfDuplex_Init()) configure also the
low level Hardware GPIO, CLOCK, CORTEX...etc) by calling the customized
HAL_UART_MspInit() API.
##### Callback registration #####
==================================
[..]
The compilation define USE_HAL_UART_REGISTER_CALLBACKS when set to 1
allows the user to configure dynamically the driver callbacks.
[..]
Use Function HAL_UART_RegisterCallback() to register a user callback.
Function HAL_UART_RegisterCallback() allows to register following callbacks:
(+) TxHalfCpltCallback : Tx Half Complete Callback.
(+) TxCpltCallback : Tx Complete Callback.
(+) RxHalfCpltCallback : Rx Half Complete Callback.
(+) RxCpltCallback : Rx Complete Callback.
(+) ErrorCallback : Error Callback.
(+) AbortCpltCallback : Abort Complete Callback.
(+) AbortTransmitCpltCallback : Abort Transmit Complete Callback.
(+) AbortReceiveCpltCallback : Abort Receive Complete Callback.
(+) MspInitCallback : UART MspInit.
(+) MspDeInitCallback : UART MspDeInit.
This function takes as parameters the HAL peripheral handle, the Callback ID
and a pointer to the user callback function.
[..]
Use function HAL_UART_UnRegisterCallback() to reset a callback to the default
weak (surcharged) function.
HAL_UART_UnRegisterCallback() takes as parameters the HAL peripheral handle,
and the Callback ID.
This function allows to reset following callbacks:
(+) TxHalfCpltCallback : Tx Half Complete Callback.
(+) TxCpltCallback : Tx Complete Callback.
(+) RxHalfCpltCallback : Rx Half Complete Callback.
(+) RxCpltCallback : Rx Complete Callback.
(+) ErrorCallback : Error Callback.
(+) AbortCpltCallback : Abort Complete Callback.
(+) AbortTransmitCpltCallback : Abort Transmit Complete Callback.
(+) AbortReceiveCpltCallback : Abort Receive Complete Callback.
(+) MspInitCallback : UART MspInit.
(+) MspDeInitCallback : UART MspDeInit.
[..]
For specific callback RxEventCallback, use dedicated registration/reset functions:
respectively HAL_UART_RegisterRxEventCallback() , HAL_UART_UnRegisterRxEventCallback().
[..]
By default, after the HAL_UART_Init() and when the state is HAL_UART_STATE_RESET
all callbacks are set to the corresponding weak (surcharged) functions:
examples HAL_UART_TxCpltCallback(), HAL_UART_RxHalfCpltCallback().
Exception done for MspInit and MspDeInit functions that are respectively
reset to the legacy weak (surcharged) functions in the HAL_UART_Init()
and HAL_UART_DeInit() only when these callbacks are null (not registered beforehand).
If not, MspInit or MspDeInit are not null, the HAL_UART_Init() and HAL_UART_DeInit()
keep and use the user MspInit/MspDeInit callbacks (registered beforehand).
[..]
Callbacks can be registered/unregistered in HAL_UART_STATE_READY state only.
Exception done MspInit/MspDeInit that can be registered/unregistered
in HAL_UART_STATE_READY or HAL_UART_STATE_RESET state, thus registered (user)
MspInit/DeInit callbacks can be used during the Init/DeInit.
In that case first register the MspInit/MspDeInit user callbacks
using HAL_UART_RegisterCallback() before calling HAL_UART_DeInit()
or HAL_UART_Init() function.
[..]
When The compilation define USE_HAL_UART_REGISTER_CALLBACKS is set to 0 or
not defined, the callback registration feature is not available
and weak (surcharged) callbacks are used.
[..]
Three operation modes are available within this driver :
*** Polling mode IO operation ***
=================================
[..]
(+) Send an amount of data in blocking mode using HAL_UART_Transmit()
(+) Receive an amount of data in blocking mode using HAL_UART_Receive()
*** Interrupt mode IO operation ***
===================================
[..]
(+) Send an amount of data in non blocking mode using HAL_UART_Transmit_IT()
(+) At transmission end of transfer HAL_UART_TxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_UART_TxCpltCallback
(+) Receive an amount of data in non blocking mode using HAL_UART_Receive_IT()
(+) At reception end of transfer HAL_UART_RxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_UART_RxCpltCallback
(+) In case of transfer Error, HAL_UART_ErrorCallback() function is executed and user can
add his own code by customization of function pointer HAL_UART_ErrorCallback
*** DMA mode IO operation ***
==============================
[..]
(+) Send an amount of data in non blocking mode (DMA) using HAL_UART_Transmit_DMA()
(+) At transmission end of half transfer HAL_UART_TxHalfCpltCallback is executed and user can
add his own code by customization of function pointer HAL_UART_TxHalfCpltCallback
(+) At transmission end of transfer HAL_UART_TxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_UART_TxCpltCallback
(+) Receive an amount of data in non blocking mode (DMA) using HAL_UART_Receive_DMA()
(+) At reception end of half transfer HAL_UART_RxHalfCpltCallback is executed and user can
add his own code by customization of function pointer HAL_UART_RxHalfCpltCallback
(+) At reception end of transfer HAL_UART_RxCpltCallback is executed and user can
add his own code by customization of function pointer HAL_UART_RxCpltCallback
(+) In case of transfer Error, HAL_UART_ErrorCallback() function is executed and user can
add his own code by customization of function pointer HAL_UART_ErrorCallback
(+) Pause the DMA Transfer using HAL_UART_DMAPause()
(+) Resume the DMA Transfer using HAL_UART_DMAResume()
(+) Stop the DMA Transfer using HAL_UART_DMAStop()
[..] This subsection also provides a set of additional functions providing enhanced reception
services to user. (For example, these functions allow application to handle use cases
where number of data to be received is unknown).
(#) Compared to standard reception services which only consider number of received
data elements as reception completion criteria, these functions also consider additional events
as triggers for updating reception status to caller :
(+) Detection of inactivity period (RX line has not been active for a given period).
(++) RX inactivity detected by IDLE event, i.e. RX line has been in idle state (normally high state)
for 1 frame time, after last received byte.
(#) There are two mode of transfer:
(+) Blocking mode: The reception is performed in polling mode, until either expected number of data is received,
or till IDLE event occurs. Reception is handled only during function execution.
When function exits, no data reception could occur. HAL status and number of actually received data elements,
are returned by function after finishing transfer.
(+) Non-Blocking mode: The reception is performed using Interrupts or DMA.
These API's return the HAL status.
The end of the data processing will be indicated through the
dedicated UART IRQ when using Interrupt mode or the DMA IRQ when using DMA mode.
The HAL_UARTEx_RxEventCallback() user callback will be executed during Receive process
The HAL_UART_ErrorCallback()user callback will be executed when a reception error is detected.
(#) Blocking mode API:
(+) HAL_UARTEx_ReceiveToIdle()
(#) Non-Blocking mode API with Interrupt:
(+) HAL_UARTEx_ReceiveToIdle_IT()
(#) Non-Blocking mode API with DMA:
(+) HAL_UARTEx_ReceiveToIdle_DMA()
*** UART HAL driver macros list ***
=============================================
[..]
Below the list of most used macros in UART HAL driver.
(+) __HAL_UART_ENABLE: Enable the UART peripheral
(+) __HAL_UART_DISABLE: Disable the UART peripheral
(+) __HAL_UART_GET_FLAG : Check whether the specified UART flag is set or not
(+) __HAL_UART_CLEAR_FLAG : Clear the specified UART pending flag
(+) __HAL_UART_ENABLE_IT: Enable the specified UART interrupt
(+) __HAL_UART_DISABLE_IT: Disable the specified UART interrupt
(+) __HAL_UART_GET_IT_SOURCE: Check whether the specified UART interrupt has occurred or not
[..]
(@) You can refer to the UART HAL driver header file for more useful macros
@endverbatim
[..]
(@) Additional remark: If the parity is enabled, then the MSB bit of the data written
in the data register is transmitted but is changed by the parity bit.
Depending on the frame length defined by the M bit (8-bits or 9-bits),
the possible UART frame formats are as listed in the following table:
+-------------------------------------------------------------+
| M bit | PCE bit | UART frame |
|---------------------|---------------------------------------|
| 0 | 0 | | SB | 8 bit data | STB | |
|---------|-----------|---------------------------------------|
| 0 | 1 | | SB | 7 bit data | PB | STB | |
|---------|-----------|---------------------------------------|
| 1 | 0 | | SB | 9 bit data | STB | |
|---------|-----------|---------------------------------------|
| 1 | 1 | | SB | 8 bit data | PB | STB | |
+-------------------------------------------------------------+
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/** @addtogroup STM32F1xx_HAL_Driver
* @{
*/
/** @defgroup UART UART
* @brief HAL UART module driver
* @{
*/
#ifdef HAL_UART_MODULE_ENABLED
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @addtogroup UART_Private_Constants
* @{
*/
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/** @addtogroup UART_Private_Functions UART Private Functions
* @{
*/
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
void UART_InitCallbacksToDefault(UART_HandleTypeDef *huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
static void UART_EndTxTransfer(UART_HandleTypeDef *huart);
static void UART_EndRxTransfer(UART_HandleTypeDef *huart);
static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma);
static void UART_DMAReceiveCplt(DMA_HandleTypeDef *hdma);
static void UART_DMATxHalfCplt(DMA_HandleTypeDef *hdma);
static void UART_DMARxHalfCplt(DMA_HandleTypeDef *hdma);
static void UART_DMAError(DMA_HandleTypeDef *hdma);
static void UART_DMAAbortOnError(DMA_HandleTypeDef *hdma);
static void UART_DMATxAbortCallback(DMA_HandleTypeDef *hdma);
static void UART_DMARxAbortCallback(DMA_HandleTypeDef *hdma);
static void UART_DMATxOnlyAbortCallback(DMA_HandleTypeDef *hdma);
static void UART_DMARxOnlyAbortCallback(DMA_HandleTypeDef *hdma);
static HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart);
static HAL_StatusTypeDef UART_EndTransmit_IT(UART_HandleTypeDef *huart);
static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart);
static HAL_StatusTypeDef UART_WaitOnFlagUntilTimeout(UART_HandleTypeDef *huart, uint32_t Flag, FlagStatus Status,
uint32_t Tickstart, uint32_t Timeout);
static void UART_SetConfig(UART_HandleTypeDef *huart);
/**
* @}
*/
/* Exported functions ---------------------------------------------------------*/
/** @defgroup UART_Exported_Functions UART Exported Functions
* @{
*/
/** @defgroup UART_Exported_Functions_Group1 Initialization and de-initialization functions
* @brief Initialization and Configuration functions
*
@verbatim
===============================================================================
##### Initialization and Configuration functions #####
===============================================================================
[..]
This subsection provides a set of functions allowing to initialize the USARTx or the UARTy
in asynchronous mode.
(+) For the asynchronous mode only these parameters can be configured:
(++) Baud Rate
(++) Word Length
(++) Stop Bit
(++) Parity: If the parity is enabled, then the MSB bit of the data written
in the data register is transmitted but is changed by the parity bit.
Depending on the frame length defined by the M bit (8-bits or 9-bits),
please refer to Reference manual for possible UART frame formats.
(++) Hardware flow control
(++) Receiver/transmitter modes
(++) Over Sampling Method
[..]
The HAL_UART_Init(), HAL_HalfDuplex_Init(), HAL_LIN_Init() and HAL_MultiProcessor_Init() APIs
follow respectively the UART asynchronous, UART Half duplex, LIN and Multi-Processor configuration
procedures (details for the procedures are available in reference manuals
(RM0008 for STM32F10Xxx MCUs and RM0041 for STM32F100xx MCUs)).
@endverbatim
* @{
*/
/**
* @brief Initializes the UART mode according to the specified parameters in
* the UART_InitTypeDef and create the associated handle.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)
{
/* Check the UART handle allocation */
if (huart == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
if (huart->Init.HwFlowCtl != UART_HWCONTROL_NONE)
{
/* The hardware flow control is available only for USART1, USART2 and USART3 */
assert_param(IS_UART_HWFLOW_INSTANCE(huart->Instance));
assert_param(IS_UART_HARDWARE_FLOW_CONTROL(huart->Init.HwFlowCtl));
}
else
{
assert_param(IS_UART_INSTANCE(huart->Instance));
}
assert_param(IS_UART_WORD_LENGTH(huart->Init.WordLength));
#if defined(USART_CR1_OVER8)
assert_param(IS_UART_OVERSAMPLING(huart->Init.OverSampling));
#endif /* USART_CR1_OVER8 */
if (huart->gState == HAL_UART_STATE_RESET)
{
/* Allocate lock resource and initialize it */
huart->Lock = HAL_UNLOCKED;
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
UART_InitCallbacksToDefault(huart);
if (huart->MspInitCallback == NULL)
{
huart->MspInitCallback = HAL_UART_MspInit;
}
/* Init the low level hardware */
huart->MspInitCallback(huart);
#else
/* Init the low level hardware : GPIO, CLOCK */
HAL_UART_MspInit(huart);
#endif /* (USE_HAL_UART_REGISTER_CALLBACKS) */
}
huart->gState = HAL_UART_STATE_BUSY;
/* Disable the peripheral */
__HAL_UART_DISABLE(huart);
/* Set the UART Communication parameters */
UART_SetConfig(huart);
/* In asynchronous mode, the following bits must be kept cleared:
- LINEN and CLKEN bits in the USART_CR2 register,
- SCEN, HDSEL and IREN bits in the USART_CR3 register.*/
CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN));
CLEAR_BIT(huart->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN));
/* Enable the peripheral */
__HAL_UART_ENABLE(huart);
/* Initialize the UART state */
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_READY;
huart->RxState = HAL_UART_STATE_READY;
huart->RxEventType = HAL_UART_RXEVENT_TC;
return HAL_OK;
}
/**
* @brief Initializes the half-duplex mode according to the specified
* parameters in the UART_InitTypeDef and create the associated handle.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HalfDuplex_Init(UART_HandleTypeDef *huart)
{
/* Check the UART handle allocation */
if (huart == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_UART_HALFDUPLEX_INSTANCE(huart->Instance));
assert_param(IS_UART_WORD_LENGTH(huart->Init.WordLength));
#if defined(USART_CR1_OVER8)
assert_param(IS_UART_OVERSAMPLING(huart->Init.OverSampling));
#endif /* USART_CR1_OVER8 */
if (huart->gState == HAL_UART_STATE_RESET)
{
/* Allocate lock resource and initialize it */
huart->Lock = HAL_UNLOCKED;
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
UART_InitCallbacksToDefault(huart);
if (huart->MspInitCallback == NULL)
{
huart->MspInitCallback = HAL_UART_MspInit;
}
/* Init the low level hardware */
huart->MspInitCallback(huart);
#else
/* Init the low level hardware : GPIO, CLOCK */
HAL_UART_MspInit(huart);
#endif /* (USE_HAL_UART_REGISTER_CALLBACKS) */
}
huart->gState = HAL_UART_STATE_BUSY;
/* Disable the peripheral */
__HAL_UART_DISABLE(huart);
/* Set the UART Communication parameters */
UART_SetConfig(huart);
/* In half-duplex mode, the following bits must be kept cleared:
- LINEN and CLKEN bits in the USART_CR2 register,
- SCEN and IREN bits in the USART_CR3 register.*/
CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN));
CLEAR_BIT(huart->Instance->CR3, (USART_CR3_IREN | USART_CR3_SCEN));
/* Enable the Half-Duplex mode by setting the HDSEL bit in the CR3 register */
SET_BIT(huart->Instance->CR3, USART_CR3_HDSEL);
/* Enable the peripheral */
__HAL_UART_ENABLE(huart);
/* Initialize the UART state*/
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_READY;
huart->RxState = HAL_UART_STATE_READY;
huart->RxEventType = HAL_UART_RXEVENT_TC;
return HAL_OK;
}
/**
* @brief Initializes the LIN mode according to the specified
* parameters in the UART_InitTypeDef and create the associated handle.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param BreakDetectLength Specifies the LIN break detection length.
* This parameter can be one of the following values:
* @arg UART_LINBREAKDETECTLENGTH_10B: 10-bit break detection
* @arg UART_LINBREAKDETECTLENGTH_11B: 11-bit break detection
* @retval HAL status
*/
HAL_StatusTypeDef HAL_LIN_Init(UART_HandleTypeDef *huart, uint32_t BreakDetectLength)
{
/* Check the UART handle allocation */
if (huart == NULL)
{
return HAL_ERROR;
}
/* Check the LIN UART instance */
assert_param(IS_UART_LIN_INSTANCE(huart->Instance));
/* Check the Break detection length parameter */
assert_param(IS_UART_LIN_BREAK_DETECT_LENGTH(BreakDetectLength));
assert_param(IS_UART_LIN_WORD_LENGTH(huart->Init.WordLength));
#if defined(USART_CR1_OVER8)
assert_param(IS_UART_LIN_OVERSAMPLING(huart->Init.OverSampling));
#endif /* USART_CR1_OVER8 */
if (huart->gState == HAL_UART_STATE_RESET)
{
/* Allocate lock resource and initialize it */
huart->Lock = HAL_UNLOCKED;
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
UART_InitCallbacksToDefault(huart);
if (huart->MspInitCallback == NULL)
{
huart->MspInitCallback = HAL_UART_MspInit;
}
/* Init the low level hardware */
huart->MspInitCallback(huart);
#else
/* Init the low level hardware : GPIO, CLOCK */
HAL_UART_MspInit(huart);
#endif /* (USE_HAL_UART_REGISTER_CALLBACKS) */
}
huart->gState = HAL_UART_STATE_BUSY;
/* Disable the peripheral */
__HAL_UART_DISABLE(huart);
/* Set the UART Communication parameters */
UART_SetConfig(huart);
/* In LIN mode, the following bits must be kept cleared:
- CLKEN bits in the USART_CR2 register,
- SCEN, HDSEL and IREN bits in the USART_CR3 register.*/
CLEAR_BIT(huart->Instance->CR2, (USART_CR2_CLKEN));
CLEAR_BIT(huart->Instance->CR3, (USART_CR3_HDSEL | USART_CR3_IREN | USART_CR3_SCEN));
/* Enable the LIN mode by setting the LINEN bit in the CR2 register */
SET_BIT(huart->Instance->CR2, USART_CR2_LINEN);
/* Set the USART LIN Break detection length. */
CLEAR_BIT(huart->Instance->CR2, USART_CR2_LBDL);
SET_BIT(huart->Instance->CR2, BreakDetectLength);
/* Enable the peripheral */
__HAL_UART_ENABLE(huart);
/* Initialize the UART state*/
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_READY;
huart->RxState = HAL_UART_STATE_READY;
huart->RxEventType = HAL_UART_RXEVENT_TC;
return HAL_OK;
}
/**
* @brief Initializes the Multi-Processor mode according to the specified
* parameters in the UART_InitTypeDef and create the associated handle.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param Address USART address
* @param WakeUpMethod specifies the USART wake-up method.
* This parameter can be one of the following values:
* @arg UART_WAKEUPMETHOD_IDLELINE: Wake-up by an idle line detection
* @arg UART_WAKEUPMETHOD_ADDRESSMARK: Wake-up by an address mark
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MultiProcessor_Init(UART_HandleTypeDef *huart, uint8_t Address, uint32_t WakeUpMethod)
{
/* Check the UART handle allocation */
if (huart == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_UART_INSTANCE(huart->Instance));
/* Check the Address & wake up method parameters */
assert_param(IS_UART_WAKEUPMETHOD(WakeUpMethod));
assert_param(IS_UART_ADDRESS(Address));
assert_param(IS_UART_WORD_LENGTH(huart->Init.WordLength));
#if defined(USART_CR1_OVER8)
assert_param(IS_UART_OVERSAMPLING(huart->Init.OverSampling));
#endif /* USART_CR1_OVER8 */
if (huart->gState == HAL_UART_STATE_RESET)
{
/* Allocate lock resource and initialize it */
huart->Lock = HAL_UNLOCKED;
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
UART_InitCallbacksToDefault(huart);
if (huart->MspInitCallback == NULL)
{
huart->MspInitCallback = HAL_UART_MspInit;
}
/* Init the low level hardware */
huart->MspInitCallback(huart);
#else
/* Init the low level hardware : GPIO, CLOCK */
HAL_UART_MspInit(huart);
#endif /* (USE_HAL_UART_REGISTER_CALLBACKS) */
}
huart->gState = HAL_UART_STATE_BUSY;
/* Disable the peripheral */
__HAL_UART_DISABLE(huart);
/* Set the UART Communication parameters */
UART_SetConfig(huart);
/* In Multi-Processor mode, the following bits must be kept cleared:
- LINEN and CLKEN bits in the USART_CR2 register,
- SCEN, HDSEL and IREN bits in the USART_CR3 register */
CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN));
CLEAR_BIT(huart->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN));
/* Set the USART address node */
CLEAR_BIT(huart->Instance->CR2, USART_CR2_ADD);
SET_BIT(huart->Instance->CR2, Address);
/* Set the wake up method by setting the WAKE bit in the CR1 register */
CLEAR_BIT(huart->Instance->CR1, USART_CR1_WAKE);
SET_BIT(huart->Instance->CR1, WakeUpMethod);
/* Enable the peripheral */
__HAL_UART_ENABLE(huart);
/* Initialize the UART state */
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_READY;
huart->RxState = HAL_UART_STATE_READY;
huart->RxEventType = HAL_UART_RXEVENT_TC;
return HAL_OK;
}
/**
* @brief DeInitializes the UART peripheral.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_DeInit(UART_HandleTypeDef *huart)
{
/* Check the UART handle allocation */
if (huart == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_UART_INSTANCE(huart->Instance));
huart->gState = HAL_UART_STATE_BUSY;
/* Disable the Peripheral */
__HAL_UART_DISABLE(huart);
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
if (huart->MspDeInitCallback == NULL)
{
huart->MspDeInitCallback = HAL_UART_MspDeInit;
}
/* DeInit the low level hardware */
huart->MspDeInitCallback(huart);
#else
/* DeInit the low level hardware */
HAL_UART_MspDeInit(huart);
#endif /* (USE_HAL_UART_REGISTER_CALLBACKS) */
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_RESET;
huart->RxState = HAL_UART_STATE_RESET;
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
huart->RxEventType = HAL_UART_RXEVENT_TC;
/* Process Unlock */
__HAL_UNLOCK(huart);
return HAL_OK;
}
/**
* @brief UART MSP Init.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval None
*/
__weak void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_UART_MspInit could be implemented in the user file
*/
}
/**
* @brief UART MSP DeInit.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval None
*/
__weak void HAL_UART_MspDeInit(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_UART_MspDeInit could be implemented in the user file
*/
}
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/**
* @brief Register a User UART Callback
* To be used instead of the weak predefined callback
* @note The HAL_UART_RegisterCallback() may be called before HAL_UART_Init(), HAL_HalfDuplex_Init(), HAL_LIN_Init(),
* HAL_MultiProcessor_Init() to register callbacks for HAL_UART_MSPINIT_CB_ID and HAL_UART_MSPDEINIT_CB_ID
* @param huart uart handle
* @param CallbackID ID of the callback to be registered
* This parameter can be one of the following values:
* @arg @ref HAL_UART_TX_HALFCOMPLETE_CB_ID Tx Half Complete Callback ID
* @arg @ref HAL_UART_TX_COMPLETE_CB_ID Tx Complete Callback ID
* @arg @ref HAL_UART_RX_HALFCOMPLETE_CB_ID Rx Half Complete Callback ID
* @arg @ref HAL_UART_RX_COMPLETE_CB_ID Rx Complete Callback ID
* @arg @ref HAL_UART_ERROR_CB_ID Error Callback ID
* @arg @ref HAL_UART_ABORT_COMPLETE_CB_ID Abort Complete Callback ID
* @arg @ref HAL_UART_ABORT_TRANSMIT_COMPLETE_CB_ID Abort Transmit Complete Callback ID
* @arg @ref HAL_UART_ABORT_RECEIVE_COMPLETE_CB_ID Abort Receive Complete Callback ID
* @arg @ref HAL_UART_MSPINIT_CB_ID MspInit Callback ID
* @arg @ref HAL_UART_MSPDEINIT_CB_ID MspDeInit Callback ID
* @param pCallback pointer to the Callback function
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_RegisterCallback(UART_HandleTypeDef *huart, HAL_UART_CallbackIDTypeDef CallbackID,
pUART_CallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
/* Update the error code */
huart->ErrorCode |= HAL_UART_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
if (huart->gState == HAL_UART_STATE_READY)
{
switch (CallbackID)
{
case HAL_UART_TX_HALFCOMPLETE_CB_ID :
huart->TxHalfCpltCallback = pCallback;
break;
case HAL_UART_TX_COMPLETE_CB_ID :
huart->TxCpltCallback = pCallback;
break;
case HAL_UART_RX_HALFCOMPLETE_CB_ID :
huart->RxHalfCpltCallback = pCallback;
break;
case HAL_UART_RX_COMPLETE_CB_ID :
huart->RxCpltCallback = pCallback;
break;
case HAL_UART_ERROR_CB_ID :
huart->ErrorCallback = pCallback;
break;
case HAL_UART_ABORT_COMPLETE_CB_ID :
huart->AbortCpltCallback = pCallback;
break;
case HAL_UART_ABORT_TRANSMIT_COMPLETE_CB_ID :
huart->AbortTransmitCpltCallback = pCallback;
break;
case HAL_UART_ABORT_RECEIVE_COMPLETE_CB_ID :
huart->AbortReceiveCpltCallback = pCallback;
break;
case HAL_UART_MSPINIT_CB_ID :
huart->MspInitCallback = pCallback;
break;
case HAL_UART_MSPDEINIT_CB_ID :
huart->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
huart->ErrorCode |= HAL_UART_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (huart->gState == HAL_UART_STATE_RESET)
{
switch (CallbackID)
{
case HAL_UART_MSPINIT_CB_ID :
huart->MspInitCallback = pCallback;
break;
case HAL_UART_MSPDEINIT_CB_ID :
huart->MspDeInitCallback = pCallback;
break;
default :
/* Update the error code */
huart->ErrorCode |= HAL_UART_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
huart->ErrorCode |= HAL_UART_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
return status;
}
/**
* @brief Unregister an UART Callback
* UART callaback is redirected to the weak predefined callback
* @note The HAL_UART_UnRegisterCallback() may be called before HAL_UART_Init(), HAL_HalfDuplex_Init(),
* HAL_LIN_Init(), HAL_MultiProcessor_Init() to un-register callbacks for HAL_UART_MSPINIT_CB_ID
* and HAL_UART_MSPDEINIT_CB_ID
* @param huart uart handle
* @param CallbackID ID of the callback to be unregistered
* This parameter can be one of the following values:
* @arg @ref HAL_UART_TX_HALFCOMPLETE_CB_ID Tx Half Complete Callback ID
* @arg @ref HAL_UART_TX_COMPLETE_CB_ID Tx Complete Callback ID
* @arg @ref HAL_UART_RX_HALFCOMPLETE_CB_ID Rx Half Complete Callback ID
* @arg @ref HAL_UART_RX_COMPLETE_CB_ID Rx Complete Callback ID
* @arg @ref HAL_UART_ERROR_CB_ID Error Callback ID
* @arg @ref HAL_UART_ABORT_COMPLETE_CB_ID Abort Complete Callback ID
* @arg @ref HAL_UART_ABORT_TRANSMIT_COMPLETE_CB_ID Abort Transmit Complete Callback ID
* @arg @ref HAL_UART_ABORT_RECEIVE_COMPLETE_CB_ID Abort Receive Complete Callback ID
* @arg @ref HAL_UART_MSPINIT_CB_ID MspInit Callback ID
* @arg @ref HAL_UART_MSPDEINIT_CB_ID MspDeInit Callback ID
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_UnRegisterCallback(UART_HandleTypeDef *huart, HAL_UART_CallbackIDTypeDef CallbackID)
{
HAL_StatusTypeDef status = HAL_OK;
if (HAL_UART_STATE_READY == huart->gState)
{
switch (CallbackID)
{
case HAL_UART_TX_HALFCOMPLETE_CB_ID :
huart->TxHalfCpltCallback = HAL_UART_TxHalfCpltCallback; /* Legacy weak TxHalfCpltCallback */
break;
case HAL_UART_TX_COMPLETE_CB_ID :
huart->TxCpltCallback = HAL_UART_TxCpltCallback; /* Legacy weak TxCpltCallback */
break;
case HAL_UART_RX_HALFCOMPLETE_CB_ID :
huart->RxHalfCpltCallback = HAL_UART_RxHalfCpltCallback; /* Legacy weak RxHalfCpltCallback */
break;
case HAL_UART_RX_COMPLETE_CB_ID :
huart->RxCpltCallback = HAL_UART_RxCpltCallback; /* Legacy weak RxCpltCallback */
break;
case HAL_UART_ERROR_CB_ID :
huart->ErrorCallback = HAL_UART_ErrorCallback; /* Legacy weak ErrorCallback */
break;
case HAL_UART_ABORT_COMPLETE_CB_ID :
huart->AbortCpltCallback = HAL_UART_AbortCpltCallback; /* Legacy weak AbortCpltCallback */
break;
case HAL_UART_ABORT_TRANSMIT_COMPLETE_CB_ID :
huart->AbortTransmitCpltCallback = HAL_UART_AbortTransmitCpltCallback; /* Legacy weak AbortTransmitCpltCallback */
break;
case HAL_UART_ABORT_RECEIVE_COMPLETE_CB_ID :
huart->AbortReceiveCpltCallback = HAL_UART_AbortReceiveCpltCallback; /* Legacy weak AbortReceiveCpltCallback */
break;
case HAL_UART_MSPINIT_CB_ID :
huart->MspInitCallback = HAL_UART_MspInit; /* Legacy weak MspInitCallback */
break;
case HAL_UART_MSPDEINIT_CB_ID :
huart->MspDeInitCallback = HAL_UART_MspDeInit; /* Legacy weak MspDeInitCallback */
break;
default :
/* Update the error code */
huart->ErrorCode |= HAL_UART_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else if (HAL_UART_STATE_RESET == huart->gState)
{
switch (CallbackID)
{
case HAL_UART_MSPINIT_CB_ID :
huart->MspInitCallback = HAL_UART_MspInit;
break;
case HAL_UART_MSPDEINIT_CB_ID :
huart->MspDeInitCallback = HAL_UART_MspDeInit;
break;
default :
/* Update the error code */
huart->ErrorCode |= HAL_UART_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
break;
}
}
else
{
/* Update the error code */
huart->ErrorCode |= HAL_UART_ERROR_INVALID_CALLBACK;
/* Return error status */
status = HAL_ERROR;
}
return status;
}
/**
* @brief Register a User UART Rx Event Callback
* To be used instead of the weak predefined callback
* @param huart Uart handle
* @param pCallback Pointer to the Rx Event Callback function
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_RegisterRxEventCallback(UART_HandleTypeDef *huart, pUART_RxEventCallbackTypeDef pCallback)
{
HAL_StatusTypeDef status = HAL_OK;
if (pCallback == NULL)
{
huart->ErrorCode |= HAL_UART_ERROR_INVALID_CALLBACK;
return HAL_ERROR;
}
/* Process locked */
__HAL_LOCK(huart);
if (huart->gState == HAL_UART_STATE_READY)
{
huart->RxEventCallback = pCallback;
}
else
{
huart->ErrorCode |= HAL_UART_ERROR_INVALID_CALLBACK;
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(huart);
return status;
}
/**
* @brief UnRegister the UART Rx Event Callback
* UART Rx Event Callback is redirected to the weak HAL_UARTEx_RxEventCallback() predefined callback
* @param huart Uart handle
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_UnRegisterRxEventCallback(UART_HandleTypeDef *huart)
{
HAL_StatusTypeDef status = HAL_OK;
/* Process locked */
__HAL_LOCK(huart);
if (huart->gState == HAL_UART_STATE_READY)
{
huart->RxEventCallback = HAL_UARTEx_RxEventCallback; /* Legacy weak UART Rx Event Callback */
}
else
{
huart->ErrorCode |= HAL_UART_ERROR_INVALID_CALLBACK;
status = HAL_ERROR;
}
/* Release Lock */
__HAL_UNLOCK(huart);
return status;
}
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
/**
* @}
*/
/** @defgroup UART_Exported_Functions_Group2 IO operation functions
* @brief UART Transmit and Receive functions
*
@verbatim
===============================================================================
##### IO operation functions #####
===============================================================================
This subsection provides a set of functions allowing to manage the UART asynchronous
and Half duplex data transfers.
(#) There are two modes of transfer:
(+) Blocking mode: The communication is performed in polling mode.
The HAL status of all data processing is returned by the same function
after finishing transfer.
(+) Non-Blocking mode: The communication is performed using Interrupts
or DMA, these API's return the HAL status.
The end of the data processing will be indicated through the
dedicated UART IRQ when using Interrupt mode or the DMA IRQ when
using DMA mode.
The HAL_UART_TxCpltCallback(), HAL_UART_RxCpltCallback() user callbacks
will be executed respectively at the end of the transmit or receive process
The HAL_UART_ErrorCallback()user callback will be executed when a communication error is detected.
(#) Blocking mode API's are :
(+) HAL_UART_Transmit()
(+) HAL_UART_Receive()
(#) Non-Blocking mode API's with Interrupt are :
(+) HAL_UART_Transmit_IT()
(+) HAL_UART_Receive_IT()
(+) HAL_UART_IRQHandler()
(#) Non-Blocking mode API's with DMA are :
(+) HAL_UART_Transmit_DMA()
(+) HAL_UART_Receive_DMA()
(+) HAL_UART_DMAPause()
(+) HAL_UART_DMAResume()
(+) HAL_UART_DMAStop()
(#) A set of Transfer Complete Callbacks are provided in Non_Blocking mode:
(+) HAL_UART_TxHalfCpltCallback()
(+) HAL_UART_TxCpltCallback()
(+) HAL_UART_RxHalfCpltCallback()
(+) HAL_UART_RxCpltCallback()
(+) HAL_UART_ErrorCallback()
(#) Non-Blocking mode transfers could be aborted using Abort API's :
(+) HAL_UART_Abort()
(+) HAL_UART_AbortTransmit()
(+) HAL_UART_AbortReceive()
(+) HAL_UART_Abort_IT()
(+) HAL_UART_AbortTransmit_IT()
(+) HAL_UART_AbortReceive_IT()
(#) For Abort services based on interrupts (HAL_UART_Abortxxx_IT), a set of Abort Complete Callbacks are provided:
(+) HAL_UART_AbortCpltCallback()
(+) HAL_UART_AbortTransmitCpltCallback()
(+) HAL_UART_AbortReceiveCpltCallback()
(#) A Rx Event Reception Callback (Rx event notification) is available for Non_Blocking modes of enhanced reception services:
(+) HAL_UARTEx_RxEventCallback()
(#) In Non-Blocking mode transfers, possible errors are split into 2 categories.
Errors are handled as follows :
(+) Error is considered as Recoverable and non blocking : Transfer could go till end, but error severity is
to be evaluated by user : this concerns Frame Error, Parity Error or Noise Error in Interrupt mode reception .
Received character is then retrieved and stored in Rx buffer, Error code is set to allow user to identify error type,
and HAL_UART_ErrorCallback() user callback is executed. Transfer is kept ongoing on UART side.
If user wants to abort it, Abort services should be called by user.
(+) Error is considered as Blocking : Transfer could not be completed properly and is aborted.
This concerns Overrun Error In Interrupt mode reception and all errors in DMA mode.
Error code is set to allow user to identify error type, and HAL_UART_ErrorCallback() user callback is executed.
-@- In the Half duplex communication, it is forbidden to run the transmit
and receive process in parallel, the UART state HAL_UART_STATE_BUSY_TX_RX can't be useful.
@endverbatim
* @{
*/
/**
* @brief Sends an amount of data in blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data is handled as a set of u16. In this case, Size must indicate the number
* of u16 provided through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be sent
* @param Timeout Timeout duration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
const uint8_t *pdata8bits;
const uint16_t *pdata16bits;
uint32_t tickstart = 0U;
/* Check that a Tx process is not already ongoing */
if (huart->gState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_BUSY_TX;
/* Init tickstart for timeout management */
tickstart = HAL_GetTick();
huart->TxXferSize = Size;
huart->TxXferCount = Size;
/* In case of 9bits/No Parity transfer, pData needs to be handled as a uint16_t pointer */
if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
{
pdata8bits = NULL;
pdata16bits = (const uint16_t *) pData;
}
else
{
pdata8bits = pData;
pdata16bits = NULL;
}
while (huart->TxXferCount > 0U)
{
if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
{
huart->gState = HAL_UART_STATE_READY;
return HAL_TIMEOUT;
}
if (pdata8bits == NULL)
{
huart->Instance->DR = (uint16_t)(*pdata16bits & 0x01FFU);
pdata16bits++;
}
else
{
huart->Instance->DR = (uint8_t)(*pdata8bits & 0xFFU);
pdata8bits++;
}
huart->TxXferCount--;
}
if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK)
{
huart->gState = HAL_UART_STATE_READY;
return HAL_TIMEOUT;
}
/* At end of Tx process, restore huart->gState to Ready */
huart->gState = HAL_UART_STATE_READY;
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Receives an amount of data in blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must indicate the number
* of u16 available through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @param Timeout Timeout duration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
uint8_t *pdata8bits;
uint16_t *pdata16bits;
uint32_t tickstart = 0U;
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
/* Init tickstart for timeout management */
tickstart = HAL_GetTick();
huart->RxXferSize = Size;
huart->RxXferCount = Size;
/* In case of 9bits/No Parity transfer, pRxData needs to be handled as a uint16_t pointer */
if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
{
pdata8bits = NULL;
pdata16bits = (uint16_t *) pData;
}
else
{
pdata8bits = pData;
pdata16bits = NULL;
}
/* Check the remain data to be received */
while (huart->RxXferCount > 0U)
{
if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
{
huart->RxState = HAL_UART_STATE_READY;
return HAL_TIMEOUT;
}
if (pdata8bits == NULL)
{
*pdata16bits = (uint16_t)(huart->Instance->DR & 0x01FF);
pdata16bits++;
}
else
{
if ((huart->Init.WordLength == UART_WORDLENGTH_9B) || ((huart->Init.WordLength == UART_WORDLENGTH_8B) && (huart->Init.Parity == UART_PARITY_NONE)))
{
*pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
}
else
{
*pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
}
pdata8bits++;
}
huart->RxXferCount--;
}
/* At end of Rx process, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Sends an amount of data in non blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data is handled as a set of u16. In this case, Size must indicate the number
* of u16 provided through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be sent
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)
{
/* Check that a Tx process is not already ongoing */
if (huart->gState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
huart->pTxBuffPtr = pData;
huart->TxXferSize = Size;
huart->TxXferCount = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_BUSY_TX;
/* Enable the UART Transmit data register empty Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_TXE);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Receives an amount of data in non blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must indicate the number
* of u16 available through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Set Reception type to Standard reception */
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
return (UART_Start_Receive_IT(huart, pData, Size));
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Sends an amount of data in DMA mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data is handled as a set of u16. In this case, Size must indicate the number
* of u16 provided through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be sent
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)
{
const uint32_t *tmp;
/* Check that a Tx process is not already ongoing */
if (huart->gState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
huart->pTxBuffPtr = pData;
huart->TxXferSize = Size;
huart->TxXferCount = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_BUSY_TX;
/* Set the UART DMA transfer complete callback */
huart->hdmatx->XferCpltCallback = UART_DMATransmitCplt;
/* Set the UART DMA Half transfer complete callback */
huart->hdmatx->XferHalfCpltCallback = UART_DMATxHalfCplt;
/* Set the DMA error callback */
huart->hdmatx->XferErrorCallback = UART_DMAError;
/* Set the DMA abort callback */
huart->hdmatx->XferAbortCallback = NULL;
/* Enable the UART transmit DMA channel */
tmp = (const uint32_t *)&pData;
HAL_DMA_Start_IT(huart->hdmatx, *(const uint32_t *)tmp, (uint32_t)&huart->Instance->DR, Size);
/* Clear the TC flag in the SR register by writing 0 to it */
__HAL_UART_CLEAR_FLAG(huart, UART_FLAG_TC);
/* Enable the DMA transfer for transmit request by setting the DMAT bit
in the UART CR3 register */
ATOMIC_SET_BIT(huart->Instance->CR3, USART_CR3_DMAT);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Receives an amount of data in DMA mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must indicate the number
* of u16 available through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @note When the UART parity is enabled (PCE = 1) the received data contains the parity bit.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Set Reception type to Standard reception */
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
return (UART_Start_Receive_DMA(huart, pData, Size));
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Pauses the DMA Transfer.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_DMAPause(UART_HandleTypeDef *huart)
{
uint32_t dmarequest = 0x00U;
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT);
if ((huart->gState == HAL_UART_STATE_BUSY_TX) && dmarequest)
{
/* Disable the UART DMA Tx request */
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);
}
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
if ((huart->RxState == HAL_UART_STATE_BUSY_RX) && dmarequest)
{
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_PEIE);
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* Disable the UART DMA Rx request */
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
}
return HAL_OK;
}
/**
* @brief Resumes the DMA Transfer.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_DMAResume(UART_HandleTypeDef *huart)
{
if (huart->gState == HAL_UART_STATE_BUSY_TX)
{
/* Enable the UART DMA Tx request */
ATOMIC_SET_BIT(huart->Instance->CR3, USART_CR3_DMAT);
}
if (huart->RxState == HAL_UART_STATE_BUSY_RX)
{
/* Clear the Overrun flag before resuming the Rx transfer*/
__HAL_UART_CLEAR_OREFLAG(huart);
/* Re-enable PE and ERR (Frame error, noise error, overrun error) interrupts */
if (huart->Init.Parity != UART_PARITY_NONE)
{
ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);
}
ATOMIC_SET_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* Enable the UART DMA Rx request */
ATOMIC_SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);
}
return HAL_OK;
}
/**
* @brief Stops the DMA Transfer.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart)
{
uint32_t dmarequest = 0x00U;
/* The Lock is not implemented on this API to allow the user application
to call the HAL UART API under callbacks HAL_UART_TxCpltCallback() / HAL_UART_RxCpltCallback():
when calling HAL_DMA_Abort() API the DMA TX/RX Transfer complete interrupt is generated
and the correspond call back is executed HAL_UART_TxCpltCallback() / HAL_UART_RxCpltCallback()
*/
/* Stop UART DMA Tx request if ongoing */
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT);
if ((huart->gState == HAL_UART_STATE_BUSY_TX) && dmarequest)
{
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);
/* Abort the UART DMA Tx channel */
if (huart->hdmatx != NULL)
{
HAL_DMA_Abort(huart->hdmatx);
}
UART_EndTxTransfer(huart);
}
/* Stop UART DMA Rx request if ongoing */
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
if ((huart->RxState == HAL_UART_STATE_BUSY_RX) && dmarequest)
{
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/* Abort the UART DMA Rx channel */
if (huart->hdmarx != NULL)
{
HAL_DMA_Abort(huart->hdmarx);
}
UART_EndRxTransfer(huart);
}
return HAL_OK;
}
/**
* @brief Receive an amount of data in blocking mode till either the expected number of data is received or an IDLE event occurs.
* @note HAL_OK is returned if reception is completed (expected number of data has been received)
* or if reception is stopped after IDLE event (less than the expected number of data has been received)
* In this case, RxLen output parameter indicates number of data available in reception buffer.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M = 01),
* the received data is handled as a set of uint16_t. In this case, Size must indicate the number
* of uint16_t available through pData.
* @param huart UART handle.
* @param pData Pointer to data buffer (uint8_t or uint16_t data elements).
* @param Size Amount of data elements (uint8_t or uint16_t) to be received.
* @param RxLen Number of data elements finally received (could be lower than Size, in case reception ends on IDLE event)
* @param Timeout Timeout duration expressed in ms (covers the whole reception sequence).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint16_t *RxLen,
uint32_t Timeout)
{
uint8_t *pdata8bits;
uint16_t *pdata16bits;
uint32_t tickstart;
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
huart->ReceptionType = HAL_UART_RECEPTION_TOIDLE;
huart->RxEventType = HAL_UART_RXEVENT_TC;
/* Init tickstart for timeout management */
tickstart = HAL_GetTick();
huart->RxXferSize = Size;
huart->RxXferCount = Size;
/* In case of 9bits/No Parity transfer, pRxData needs to be handled as a uint16_t pointer */
if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
{
pdata8bits = NULL;
pdata16bits = (uint16_t *) pData;
}
else
{
pdata8bits = pData;
pdata16bits = NULL;
}
/* Initialize output number of received elements */
*RxLen = 0U;
/* as long as data have to be received */
while (huart->RxXferCount > 0U)
{
/* Check if IDLE flag is set */
if (__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE))
{
/* Clear IDLE flag in ISR */
__HAL_UART_CLEAR_IDLEFLAG(huart);
/* If Set, but no data ever received, clear flag without exiting loop */
/* If Set, and data has already been received, this means Idle Event is valid : End reception */
if (*RxLen > 0U)
{
huart->RxEventType = HAL_UART_RXEVENT_IDLE;
huart->RxState = HAL_UART_STATE_READY;
return HAL_OK;
}
}
/* Check if RXNE flag is set */
if (__HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE))
{
if (pdata8bits == NULL)
{
*pdata16bits = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
pdata16bits++;
}
else
{
if ((huart->Init.WordLength == UART_WORDLENGTH_9B) || ((huart->Init.WordLength == UART_WORDLENGTH_8B) && (huart->Init.Parity == UART_PARITY_NONE)))
{
*pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
}
else
{
*pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
}
pdata8bits++;
}
/* Increment number of received elements */
*RxLen += 1U;
huart->RxXferCount--;
}
/* Check for the Timeout */
if (Timeout != HAL_MAX_DELAY)
{
if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
{
huart->RxState = HAL_UART_STATE_READY;
return HAL_TIMEOUT;
}
}
}
/* Set number of received elements in output parameter : RxLen */
*RxLen = huart->RxXferSize - huart->RxXferCount;
/* At end of Rx process, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Receive an amount of data in interrupt mode till either the expected number of data is received or an IDLE event occurs.
* @note Reception is initiated by this function call. Further progress of reception is achieved thanks
* to UART interrupts raised by RXNE and IDLE events. Callback is called at end of reception indicating
* number of received data elements.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M = 01),
* the received data is handled as a set of uint16_t. In this case, Size must indicate the number
* of uint16_t available through pData.
* @param huart UART handle.
* @param pData Pointer to data buffer (uint8_t or uint16_t data elements).
* @param Size Amount of data elements (uint8_t or uint16_t) to be received.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
HAL_StatusTypeDef status;
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Set Reception type to reception till IDLE Event*/
huart->ReceptionType = HAL_UART_RECEPTION_TOIDLE;
huart->RxEventType = HAL_UART_RXEVENT_TC;
status = UART_Start_Receive_IT(huart, pData, Size);
/* Check Rx process has been successfully started */
if (status == HAL_OK)
{
if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
{
__HAL_UART_CLEAR_IDLEFLAG(huart);
ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
}
else
{
/* In case of errors already pending when reception is started,
Interrupts may have already been raised and lead to reception abortion.
(Overrun error for instance).
In such case Reception Type has been reset to HAL_UART_RECEPTION_STANDARD. */
status = HAL_ERROR;
}
}
return status;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Receive an amount of data in DMA mode till either the expected number of data is received or an IDLE event occurs.
* @note Reception is initiated by this function call. Further progress of reception is achieved thanks
* to DMA services, transferring automatically received data elements in user reception buffer and
* calling registered callbacks at half/end of reception. UART IDLE events are also used to consider
* reception phase as ended. In all cases, callback execution will indicate number of received data elements.
* @note When the UART parity is enabled (PCE = 1), the received data contain
* the parity bit (MSB position).
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M = 01),
* the received data is handled as a set of uint16_t. In this case, Size must indicate the number
* of uint16_t available through pData.
* @param huart UART handle.
* @param pData Pointer to data buffer (uint8_t or uint16_t data elements).
* @param Size Amount of data elements (uint8_t or uint16_t) to be received.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
HAL_StatusTypeDef status;
/* Check that a Rx process is not already ongoing */
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Set Reception type to reception till IDLE Event*/
huart->ReceptionType = HAL_UART_RECEPTION_TOIDLE;
huart->RxEventType = HAL_UART_RXEVENT_TC;
status = UART_Start_Receive_DMA(huart, pData, Size);
/* Check Rx process has been successfully started */
if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
{
__HAL_UART_CLEAR_IDLEFLAG(huart);
ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
}
else
{
/* In case of errors already pending when reception is started,
Interrupts may have already been raised and lead to reception abortion.
(Overrun error for instance).
In such case Reception Type has been reset to HAL_UART_RECEPTION_STANDARD. */
status = HAL_ERROR;
}
return status;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Provide Rx Event type that has lead to RxEvent callback execution.
* @note When HAL_UARTEx_ReceiveToIdle_IT() or HAL_UARTEx_ReceiveToIdle_DMA() API are called, progress
* of reception process is provided to application through calls of Rx Event callback (either default one
* HAL_UARTEx_RxEventCallback() or user registered one). As several types of events could occur (IDLE event,
* Half Transfer, or Transfer Complete), this function allows to retrieve the Rx Event type that has lead
* to Rx Event callback execution.
* @note This function is expected to be called within the user implementation of Rx Event Callback,
* in order to provide the accurate value :
* In Interrupt Mode :
* - HAL_UART_RXEVENT_TC : when Reception has been completed (expected nb of data has been received)
* - HAL_UART_RXEVENT_IDLE : when Idle event occurred prior reception has been completed (nb of
* received data is lower than expected one)
* In DMA Mode :
* - HAL_UART_RXEVENT_TC : when Reception has been completed (expected nb of data has been received)
* - HAL_UART_RXEVENT_HT : when half of expected nb of data has been received
* - HAL_UART_RXEVENT_IDLE : when Idle event occurred prior reception has been completed (nb of
* received data is lower than expected one).
* In DMA mode, RxEvent callback could be called several times;
* When DMA is configured in Normal Mode, HT event does not stop Reception process;
* When DMA is configured in Circular Mode, HT, TC or IDLE events don't stop Reception process;
* @param huart UART handle.
* @retval Rx Event Type (returned value will be a value of @ref UART_RxEvent_Type_Values)
*/
HAL_UART_RxEventTypeTypeDef HAL_UARTEx_GetRxEventType(UART_HandleTypeDef *huart)
{
/* Return Rx Event type value, as stored in UART handle */
return(huart->RxEventType);
}
/**
* @brief Abort ongoing transfers (blocking mode).
* @param huart UART handle.
* @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable UART Interrupts (Tx and Rx)
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort (in case of transfer in DMA mode)
* - Set handle State to READY
* @note This procedure is executed in blocking mode : when exiting function, Abort is considered as completed.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Abort(UART_HandleTypeDef *huart)
{
/* Disable TXEIE, TCIE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE | USART_CR1_TCIE));
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* If Reception till IDLE event was ongoing, disable IDLEIE interrupt */
if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
{
ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_IDLEIE));
}
/* Disable the UART DMA Tx request if enabled */
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT))
{
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);
/* Abort the UART DMA Tx channel: use blocking DMA Abort API (no callback) */
if (huart->hdmatx != NULL)
{
/* Set the UART DMA Abort callback to Null.
No call back execution at end of DMA abort procedure */
huart->hdmatx->XferAbortCallback = NULL;
if (HAL_DMA_Abort(huart->hdmatx) != HAL_OK)
{
if (HAL_DMA_GetError(huart->hdmatx) == HAL_DMA_ERROR_TIMEOUT)
{
/* Set error code to DMA */
huart->ErrorCode = HAL_UART_ERROR_DMA;
return HAL_TIMEOUT;
}
}
}
}
/* Disable the UART DMA Rx request if enabled */
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
{
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/* Abort the UART DMA Rx channel: use blocking DMA Abort API (no callback) */
if (huart->hdmarx != NULL)
{
/* Set the UART DMA Abort callback to Null.
No call back execution at end of DMA abort procedure */
huart->hdmarx->XferAbortCallback = NULL;
if (HAL_DMA_Abort(huart->hdmarx) != HAL_OK)
{
if (HAL_DMA_GetError(huart->hdmarx) == HAL_DMA_ERROR_TIMEOUT)
{
/* Set error code to DMA */
huart->ErrorCode = HAL_UART_ERROR_DMA;
return HAL_TIMEOUT;
}
}
}
}
/* Reset Tx and Rx transfer counters */
huart->TxXferCount = 0x00U;
huart->RxXferCount = 0x00U;
/* Reset ErrorCode */
huart->ErrorCode = HAL_UART_ERROR_NONE;
/* Restore huart->RxState and huart->gState to Ready */
huart->RxState = HAL_UART_STATE_READY;
huart->gState = HAL_UART_STATE_READY;
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
return HAL_OK;
}
/**
* @brief Abort ongoing Transmit transfer (blocking mode).
* @param huart UART handle.
* @note This procedure could be used for aborting any ongoing Tx transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable UART Interrupts (Tx)
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort (in case of transfer in DMA mode)
* - Set handle State to READY
* @note This procedure is executed in blocking mode : when exiting function, Abort is considered as completed.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_AbortTransmit(UART_HandleTypeDef *huart)
{
/* Disable TXEIE and TCIE interrupts */
ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE));
/* Disable the UART DMA Tx request if enabled */
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT))
{
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);
/* Abort the UART DMA Tx channel : use blocking DMA Abort API (no callback) */
if (huart->hdmatx != NULL)
{
/* Set the UART DMA Abort callback to Null.
No call back execution at end of DMA abort procedure */
huart->hdmatx->XferAbortCallback = NULL;
if (HAL_DMA_Abort(huart->hdmatx) != HAL_OK)
{
if (HAL_DMA_GetError(huart->hdmatx) == HAL_DMA_ERROR_TIMEOUT)
{
/* Set error code to DMA */
huart->ErrorCode = HAL_UART_ERROR_DMA;
return HAL_TIMEOUT;
}
}
}
}
/* Reset Tx transfer counter */
huart->TxXferCount = 0x00U;
/* Restore huart->gState to Ready */
huart->gState = HAL_UART_STATE_READY;
return HAL_OK;
}
/**
* @brief Abort ongoing Receive transfer (blocking mode).
* @param huart UART handle.
* @note This procedure could be used for aborting any ongoing Rx transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable UART Interrupts (Rx)
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort (in case of transfer in DMA mode)
* - Set handle State to READY
* @note This procedure is executed in blocking mode : when exiting function, Abort is considered as completed.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_AbortReceive(UART_HandleTypeDef *huart)
{
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* If Reception till IDLE event was ongoing, disable IDLEIE interrupt */
if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
{
ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_IDLEIE));
}
/* Disable the UART DMA Rx request if enabled */
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
{
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/* Abort the UART DMA Rx channel : use blocking DMA Abort API (no callback) */
if (huart->hdmarx != NULL)
{
/* Set the UART DMA Abort callback to Null.
No call back execution at end of DMA abort procedure */
huart->hdmarx->XferAbortCallback = NULL;
if (HAL_DMA_Abort(huart->hdmarx) != HAL_OK)
{
if (HAL_DMA_GetError(huart->hdmarx) == HAL_DMA_ERROR_TIMEOUT)
{
/* Set error code to DMA */
huart->ErrorCode = HAL_UART_ERROR_DMA;
return HAL_TIMEOUT;
}
}
}
}
/* Reset Rx transfer counter */
huart->RxXferCount = 0x00U;
/* Restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
return HAL_OK;
}
/**
* @brief Abort ongoing transfers (Interrupt mode).
* @param huart UART handle.
* @note This procedure could be used for aborting any ongoing transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable UART Interrupts (Tx and Rx)
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort_IT (in case of transfer in DMA mode)
* - Set handle State to READY
* - At abort completion, call user abort complete callback
* @note This procedure is executed in Interrupt mode, meaning that abort procedure could be
* considered as completed only when user abort complete callback is executed (not when exiting function).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Abort_IT(UART_HandleTypeDef *huart)
{
uint32_t AbortCplt = 0x01U;
/* Disable TXEIE, TCIE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE | USART_CR1_TCIE));
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* If Reception till IDLE event was ongoing, disable IDLEIE interrupt */
if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
{
ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_IDLEIE));
}
/* If DMA Tx and/or DMA Rx Handles are associated to UART Handle, DMA Abort complete callbacks should be initialised
before any call to DMA Abort functions */
/* DMA Tx Handle is valid */
if (huart->hdmatx != NULL)
{
/* Set DMA Abort Complete callback if UART DMA Tx request if enabled.
Otherwise, set it to NULL */
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT))
{
huart->hdmatx->XferAbortCallback = UART_DMATxAbortCallback;
}
else
{
huart->hdmatx->XferAbortCallback = NULL;
}
}
/* DMA Rx Handle is valid */
if (huart->hdmarx != NULL)
{
/* Set DMA Abort Complete callback if UART DMA Rx request if enabled.
Otherwise, set it to NULL */
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
{
huart->hdmarx->XferAbortCallback = UART_DMARxAbortCallback;
}
else
{
huart->hdmarx->XferAbortCallback = NULL;
}
}
/* Disable the UART DMA Tx request if enabled */
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT))
{
/* Disable DMA Tx at UART level */
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);
/* Abort the UART DMA Tx channel : use non blocking DMA Abort API (callback) */
if (huart->hdmatx != NULL)
{
/* UART Tx DMA Abort callback has already been initialised :
will lead to call HAL_UART_AbortCpltCallback() at end of DMA abort procedure */
/* Abort DMA TX */
if (HAL_DMA_Abort_IT(huart->hdmatx) != HAL_OK)
{
huart->hdmatx->XferAbortCallback = NULL;
}
else
{
AbortCplt = 0x00U;
}
}
}
/* Disable the UART DMA Rx request if enabled */
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
{
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/* Abort the UART DMA Rx channel : use non blocking DMA Abort API (callback) */
if (huart->hdmarx != NULL)
{
/* UART Rx DMA Abort callback has already been initialised :
will lead to call HAL_UART_AbortCpltCallback() at end of DMA abort procedure */
/* Abort DMA RX */
if (HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
{
huart->hdmarx->XferAbortCallback = NULL;
AbortCplt = 0x01U;
}
else
{
AbortCplt = 0x00U;
}
}
}
/* if no DMA abort complete callback execution is required => call user Abort Complete callback */
if (AbortCplt == 0x01U)
{
/* Reset Tx and Rx transfer counters */
huart->TxXferCount = 0x00U;
huart->RxXferCount = 0x00U;
/* Reset ErrorCode */
huart->ErrorCode = HAL_UART_ERROR_NONE;
/* Restore huart->gState and huart->RxState to Ready */
huart->gState = HAL_UART_STATE_READY;
huart->RxState = HAL_UART_STATE_READY;
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
/* As no DMA to be aborted, call directly user Abort complete callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/* Call registered Abort complete callback */
huart->AbortCpltCallback(huart);
#else
/* Call legacy weak Abort complete callback */
HAL_UART_AbortCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
return HAL_OK;
}
/**
* @brief Abort ongoing Transmit transfer (Interrupt mode).
* @param huart UART handle.
* @note This procedure could be used for aborting any ongoing Tx transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable UART Interrupts (Tx)
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort_IT (in case of transfer in DMA mode)
* - Set handle State to READY
* - At abort completion, call user abort complete callback
* @note This procedure is executed in Interrupt mode, meaning that abort procedure could be
* considered as completed only when user abort complete callback is executed (not when exiting function).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_AbortTransmit_IT(UART_HandleTypeDef *huart)
{
/* Disable TXEIE and TCIE interrupts */
ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE));
/* Disable the UART DMA Tx request if enabled */
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT))
{
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);
/* Abort the UART DMA Tx channel : use blocking DMA Abort API (no callback) */
if (huart->hdmatx != NULL)
{
/* Set the UART DMA Abort callback :
will lead to call HAL_UART_AbortCpltCallback() at end of DMA abort procedure */
huart->hdmatx->XferAbortCallback = UART_DMATxOnlyAbortCallback;
/* Abort DMA TX */
if (HAL_DMA_Abort_IT(huart->hdmatx) != HAL_OK)
{
/* Call Directly huart->hdmatx->XferAbortCallback function in case of error */
huart->hdmatx->XferAbortCallback(huart->hdmatx);
}
}
else
{
/* Reset Tx transfer counter */
huart->TxXferCount = 0x00U;
/* Restore huart->gState to Ready */
huart->gState = HAL_UART_STATE_READY;
/* As no DMA to be aborted, call directly user Abort complete callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/* Call registered Abort Transmit Complete Callback */
huart->AbortTransmitCpltCallback(huart);
#else
/* Call legacy weak Abort Transmit Complete Callback */
HAL_UART_AbortTransmitCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
}
else
{
/* Reset Tx transfer counter */
huart->TxXferCount = 0x00U;
/* Restore huart->gState to Ready */
huart->gState = HAL_UART_STATE_READY;
/* As no DMA to be aborted, call directly user Abort complete callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/* Call registered Abort Transmit Complete Callback */
huart->AbortTransmitCpltCallback(huart);
#else
/* Call legacy weak Abort Transmit Complete Callback */
HAL_UART_AbortTransmitCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
return HAL_OK;
}
/**
* @brief Abort ongoing Receive transfer (Interrupt mode).
* @param huart UART handle.
* @note This procedure could be used for aborting any ongoing Rx transfer started in Interrupt or DMA mode.
* This procedure performs following operations :
* - Disable UART Interrupts (Rx)
* - Disable the DMA transfer in the peripheral register (if enabled)
* - Abort DMA transfer by calling HAL_DMA_Abort_IT (in case of transfer in DMA mode)
* - Set handle State to READY
* - At abort completion, call user abort complete callback
* @note This procedure is executed in Interrupt mode, meaning that abort procedure could be
* considered as completed only when user abort complete callback is executed (not when exiting function).
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_AbortReceive_IT(UART_HandleTypeDef *huart)
{
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* If Reception till IDLE event was ongoing, disable IDLEIE interrupt */
if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
{
ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_IDLEIE));
}
/* Disable the UART DMA Rx request if enabled */
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
{
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/* Abort the UART DMA Rx channel : use blocking DMA Abort API (no callback) */
if (huart->hdmarx != NULL)
{
/* Set the UART DMA Abort callback :
will lead to call HAL_UART_AbortCpltCallback() at end of DMA abort procedure */
huart->hdmarx->XferAbortCallback = UART_DMARxOnlyAbortCallback;
/* Abort DMA RX */
if (HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
{
/* Call Directly huart->hdmarx->XferAbortCallback function in case of error */
huart->hdmarx->XferAbortCallback(huart->hdmarx);
}
}
else
{
/* Reset Rx transfer counter */
huart->RxXferCount = 0x00U;
/* Restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
/* As no DMA to be aborted, call directly user Abort complete callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/* Call registered Abort Receive Complete Callback */
huart->AbortReceiveCpltCallback(huart);
#else
/* Call legacy weak Abort Receive Complete Callback */
HAL_UART_AbortReceiveCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
}
else
{
/* Reset Rx transfer counter */
huart->RxXferCount = 0x00U;
/* Restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
/* As no DMA to be aborted, call directly user Abort complete callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/* Call registered Abort Receive Complete Callback */
huart->AbortReceiveCpltCallback(huart);
#else
/* Call legacy weak Abort Receive Complete Callback */
HAL_UART_AbortReceiveCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
return HAL_OK;
}
/**
* @brief This function handles UART interrupt request.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval None
*/
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
uint32_t isrflags = READ_REG(huart->Instance->SR);
uint32_t cr1its = READ_REG(huart->Instance->CR1);
uint32_t cr3its = READ_REG(huart->Instance->CR3);
uint32_t errorflags = 0x00U;
uint32_t dmarequest = 0x00U;
/* If no error occurs */
errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
if (errorflags == RESET)
{
/* UART in mode Receiver -------------------------------------------------*/
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
return;
}
}
/* If some errors occur */
if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET)
|| ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
{
/* UART parity error interrupt occurred ----------------------------------*/
if (((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_PE;
}
/* UART noise error interrupt occurred -----------------------------------*/
if (((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_NE;
}
/* UART frame error interrupt occurred -----------------------------------*/
if (((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_FE;
}
/* UART Over-Run interrupt occurred --------------------------------------*/
if (((isrflags & USART_SR_ORE) != RESET) && (((cr1its & USART_CR1_RXNEIE) != RESET)
|| ((cr3its & USART_CR3_EIE) != RESET)))
{
huart->ErrorCode |= HAL_UART_ERROR_ORE;
}
/* Call UART Error Call back function if need be --------------------------*/
if (huart->ErrorCode != HAL_UART_ERROR_NONE)
{
/* UART in mode Receiver -----------------------------------------------*/
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
}
/* If Overrun error occurs, or if any error occurs in DMA mode reception,
consider error as blocking */
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest)
{
/* Blocking error : transfer is aborted
Set the UART state ready to be able to start again the process,
Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
UART_EndRxTransfer(huart);
/* Disable the UART DMA Rx request if enabled */
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
{
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/* Abort the UART DMA Rx channel */
if (huart->hdmarx != NULL)
{
/* Set the UART DMA Abort callback :
will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */
huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;
if (HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
{
/* Call Directly XferAbortCallback function in case of error */
huart->hdmarx->XferAbortCallback(huart->hdmarx);
}
}
else
{
/* Call user error callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered error callback*/
huart->ErrorCallback(huart);
#else
/*Call legacy weak error callback*/
HAL_UART_ErrorCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
}
else
{
/* Call user error callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered error callback*/
huart->ErrorCallback(huart);
#else
/*Call legacy weak error callback*/
HAL_UART_ErrorCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
}
else
{
/* Non Blocking error : transfer could go on.
Error is notified to user through user error callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered error callback*/
huart->ErrorCallback(huart);
#else
/*Call legacy weak error callback*/
HAL_UART_ErrorCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
huart->ErrorCode = HAL_UART_ERROR_NONE;
}
}
return;
} /* End if some error occurs */
/* Check current reception Mode :
If Reception till IDLE event has been selected : */
if ((huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
&& ((isrflags & USART_SR_IDLE) != 0U)
&& ((cr1its & USART_SR_IDLE) != 0U))
{
__HAL_UART_CLEAR_IDLEFLAG(huart);
/* Check if DMA mode is enabled in UART */
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
{
/* DMA mode enabled */
/* Check received length : If all expected data are received, do nothing,
(DMA cplt callback will be called).
Otherwise, if at least one data has already been received, IDLE event is to be notified to user */
uint16_t nb_remaining_rx_data = (uint16_t) __HAL_DMA_GET_COUNTER(huart->hdmarx);
if ((nb_remaining_rx_data > 0U)
&& (nb_remaining_rx_data < huart->RxXferSize))
{
/* Reception is not complete */
huart->RxXferCount = nb_remaining_rx_data;
/* In Normal mode, end DMA xfer and HAL UART Rx process*/
if (huart->hdmarx->Init.Mode != DMA_CIRCULAR)
{
/* Disable PE and ERR (Frame error, noise error, overrun error) interrupts */
ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_PEIE);
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* Disable the DMA transfer for the receiver request by resetting the DMAR bit
in the UART CR3 register */
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/* At end of Rx process, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
/* Last bytes received, so no need as the abort is immediate */
(void)HAL_DMA_Abort(huart->hdmarx);
}
/* Initialize type of RxEvent that correspond to RxEvent callback execution;
In this case, Rx Event type is Idle Event */
huart->RxEventType = HAL_UART_RXEVENT_IDLE;
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Rx Event callback*/
huart->RxEventCallback(huart, (huart->RxXferSize - huart->RxXferCount));
#else
/*Call legacy weak Rx Event callback*/
HAL_UARTEx_RxEventCallback(huart, (huart->RxXferSize - huart->RxXferCount));
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
return;
}
else
{
/* DMA mode not enabled */
/* Check received length : If all expected data are received, do nothing.
Otherwise, if at least one data has already been received, IDLE event is to be notified to user */
uint16_t nb_rx_data = huart->RxXferSize - huart->RxXferCount;
if ((huart->RxXferCount > 0U)
&& (nb_rx_data > 0U))
{
/* Disable the UART Parity Error Interrupt and RXNE interrupts */
ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
/* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* Rx process is completed, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
/* Initialize type of RxEvent that correspond to RxEvent callback execution;
In this case, Rx Event type is Idle Event */
huart->RxEventType = HAL_UART_RXEVENT_IDLE;
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Rx complete callback*/
huart->RxEventCallback(huart, nb_rx_data);
#else
/*Call legacy weak Rx Event callback*/
HAL_UARTEx_RxEventCallback(huart, nb_rx_data);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
return;
}
}
/* UART in mode Transmitter ------------------------------------------------*/
if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
{
UART_Transmit_IT(huart);
return;
}
/* UART in mode Transmitter end --------------------------------------------*/
if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
{
UART_EndTransmit_IT(huart);
return;
}
}
/**
* @brief Tx Transfer completed callbacks.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval None
*/
__weak void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_UART_TxCpltCallback could be implemented in the user file
*/
}
/**
* @brief Tx Half Transfer completed callbacks.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval None
*/
__weak void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_UART_TxHalfCpltCallback could be implemented in the user file
*/
}
/**
* @brief Rx Transfer completed callbacks.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval None
*/
__weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_UART_RxCpltCallback could be implemented in the user file
*/
}
/**
* @brief Rx Half Transfer completed callbacks.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval None
*/
__weak void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_UART_RxHalfCpltCallback could be implemented in the user file
*/
}
/**
* @brief UART error callbacks.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval None
*/
__weak void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_UART_ErrorCallback could be implemented in the user file
*/
}
/**
* @brief UART Abort Complete callback.
* @param huart UART handle.
* @retval None
*/
__weak void HAL_UART_AbortCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_UART_AbortCpltCallback can be implemented in the user file.
*/
}
/**
* @brief UART Abort Complete callback.
* @param huart UART handle.
* @retval None
*/
__weak void HAL_UART_AbortTransmitCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_UART_AbortTransmitCpltCallback can be implemented in the user file.
*/
}
/**
* @brief UART Abort Receive Complete callback.
* @param huart UART handle.
* @retval None
*/
__weak void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_UART_AbortReceiveCpltCallback can be implemented in the user file.
*/
}
/**
* @brief Reception Event Callback (Rx event notification called after use of advanced reception service).
* @param huart UART handle
* @param Size Number of data available in application reception buffer (indicates a position in
* reception buffer until which, data are available)
* @retval None
*/
__weak void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
UNUSED(Size);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_UARTEx_RxEventCallback can be implemented in the user file.
*/
}
/**
* @}
*/
/** @defgroup UART_Exported_Functions_Group3 Peripheral Control functions
* @brief UART control functions
*
@verbatim
==============================================================================
##### Peripheral Control functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to control the UART:
(+) HAL_LIN_SendBreak() API can be helpful to transmit the break character.
(+) HAL_MultiProcessor_EnterMuteMode() API can be helpful to enter the UART in mute mode.
(+) HAL_MultiProcessor_ExitMuteMode() API can be helpful to exit the UART mute mode by software.
(+) HAL_HalfDuplex_EnableTransmitter() API to enable the UART transmitter and disables the UART receiver in Half Duplex mode
(+) HAL_HalfDuplex_EnableReceiver() API to enable the UART receiver and disables the UART transmitter in Half Duplex mode
@endverbatim
* @{
*/
/**
* @brief Transmits break characters.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_LIN_SendBreak(UART_HandleTypeDef *huart)
{
/* Check the parameters */
assert_param(IS_UART_INSTANCE(huart->Instance));
/* Process Locked */
__HAL_LOCK(huart);
huart->gState = HAL_UART_STATE_BUSY;
/* Send break characters */
ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_SBK);
huart->gState = HAL_UART_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(huart);
return HAL_OK;
}
/**
* @brief Enters the UART in mute mode.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MultiProcessor_EnterMuteMode(UART_HandleTypeDef *huart)
{
/* Check the parameters */
assert_param(IS_UART_INSTANCE(huart->Instance));
/* Process Locked */
__HAL_LOCK(huart);
huart->gState = HAL_UART_STATE_BUSY;
/* Enable the USART mute mode by setting the RWU bit in the CR1 register */
ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_RWU);
huart->gState = HAL_UART_STATE_READY;
huart->RxEventType = HAL_UART_RXEVENT_TC;
/* Process Unlocked */
__HAL_UNLOCK(huart);
return HAL_OK;
}
/**
* @brief Exits the UART mute mode: wake up software.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_MultiProcessor_ExitMuteMode(UART_HandleTypeDef *huart)
{
/* Check the parameters */
assert_param(IS_UART_INSTANCE(huart->Instance));
/* Process Locked */
__HAL_LOCK(huart);
huart->gState = HAL_UART_STATE_BUSY;
/* Disable the USART mute mode by clearing the RWU bit in the CR1 register */
ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_RWU);
huart->gState = HAL_UART_STATE_READY;
huart->RxEventType = HAL_UART_RXEVENT_TC;
/* Process Unlocked */
__HAL_UNLOCK(huart);
return HAL_OK;
}
/**
* @brief Enables the UART transmitter and disables the UART receiver.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HalfDuplex_EnableTransmitter(UART_HandleTypeDef *huart)
{
uint32_t tmpreg = 0x00U;
/* Process Locked */
__HAL_LOCK(huart);
huart->gState = HAL_UART_STATE_BUSY;
/*-------------------------- USART CR1 Configuration -----------------------*/
tmpreg = huart->Instance->CR1;
/* Clear TE and RE bits */
tmpreg &= (uint32_t)~((uint32_t)(USART_CR1_TE | USART_CR1_RE));
/* Enable the USART's transmit interface by setting the TE bit in the USART CR1 register */
tmpreg |= (uint32_t)USART_CR1_TE;
/* Write to USART CR1 */
WRITE_REG(huart->Instance->CR1, (uint32_t)tmpreg);
huart->gState = HAL_UART_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(huart);
return HAL_OK;
}
/**
* @brief Enables the UART receiver and disables the UART transmitter.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_HalfDuplex_EnableReceiver(UART_HandleTypeDef *huart)
{
uint32_t tmpreg = 0x00U;
/* Process Locked */
__HAL_LOCK(huart);
huart->gState = HAL_UART_STATE_BUSY;
/*-------------------------- USART CR1 Configuration -----------------------*/
tmpreg = huart->Instance->CR1;
/* Clear TE and RE bits */
tmpreg &= (uint32_t)~((uint32_t)(USART_CR1_TE | USART_CR1_RE));
/* Enable the USART's receive interface by setting the RE bit in the USART CR1 register */
tmpreg |= (uint32_t)USART_CR1_RE;
/* Write to USART CR1 */
WRITE_REG(huart->Instance->CR1, (uint32_t)tmpreg);
huart->gState = HAL_UART_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(huart);
return HAL_OK;
}
/**
* @}
*/
/** @defgroup UART_Exported_Functions_Group4 Peripheral State and Errors functions
* @brief UART State and Errors functions
*
@verbatim
==============================================================================
##### Peripheral State and Errors functions #####
==============================================================================
[..]
This subsection provides a set of functions allowing to return the State of
UART communication process, return Peripheral Errors occurred during communication
process
(+) HAL_UART_GetState() API can be helpful to check in run-time the state of the UART peripheral.
(+) HAL_UART_GetError() check in run-time errors that could be occurred during communication.
@endverbatim
* @{
*/
/**
* @brief Returns the UART state.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL state
*/
HAL_UART_StateTypeDef HAL_UART_GetState(const UART_HandleTypeDef *huart)
{
uint32_t temp1 = 0x00U, temp2 = 0x00U;
temp1 = huart->gState;
temp2 = huart->RxState;
return (HAL_UART_StateTypeDef)(temp1 | temp2);
}
/**
* @brief Return the UART error code
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART.
* @retval UART Error Code
*/
uint32_t HAL_UART_GetError(const UART_HandleTypeDef *huart)
{
return huart->ErrorCode;
}
/**
* @}
*/
/**
* @}
*/
/** @defgroup UART_Private_Functions UART Private Functions
* @{
*/
/**
* @brief Initialize the callbacks to their default values.
* @param huart UART handle.
* @retval none
*/
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
void UART_InitCallbacksToDefault(UART_HandleTypeDef *huart)
{
/* Init the UART Callback settings */
huart->TxHalfCpltCallback = HAL_UART_TxHalfCpltCallback; /* Legacy weak TxHalfCpltCallback */
huart->TxCpltCallback = HAL_UART_TxCpltCallback; /* Legacy weak TxCpltCallback */
huart->RxHalfCpltCallback = HAL_UART_RxHalfCpltCallback; /* Legacy weak RxHalfCpltCallback */
huart->RxCpltCallback = HAL_UART_RxCpltCallback; /* Legacy weak RxCpltCallback */
huart->ErrorCallback = HAL_UART_ErrorCallback; /* Legacy weak ErrorCallback */
huart->AbortCpltCallback = HAL_UART_AbortCpltCallback; /* Legacy weak AbortCpltCallback */
huart->AbortTransmitCpltCallback = HAL_UART_AbortTransmitCpltCallback; /* Legacy weak AbortTransmitCpltCallback */
huart->AbortReceiveCpltCallback = HAL_UART_AbortReceiveCpltCallback; /* Legacy weak AbortReceiveCpltCallback */
huart->RxEventCallback = HAL_UARTEx_RxEventCallback; /* Legacy weak RxEventCallback */
}
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
/**
* @brief DMA UART transmit process complete callback.
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* DMA Normal mode*/
if ((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
{
huart->TxXferCount = 0x00U;
/* Disable the DMA transfer for transmit request by setting the DMAT bit
in the UART CR3 register */
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAT);
/* Enable the UART Transmit Complete Interrupt */
ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_TCIE);
}
/* DMA Circular mode */
else
{
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Tx complete callback*/
huart->TxCpltCallback(huart);
#else
/*Call legacy weak Tx complete callback*/
HAL_UART_TxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
}
/**
* @brief DMA UART transmit process half complete callback
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void UART_DMATxHalfCplt(DMA_HandleTypeDef *hdma)
{
UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Tx complete callback*/
huart->TxHalfCpltCallback(huart);
#else
/*Call legacy weak Tx complete callback*/
HAL_UART_TxHalfCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
/**
* @brief DMA UART receive process complete callback.
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void UART_DMAReceiveCplt(DMA_HandleTypeDef *hdma)
{
UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* DMA Normal mode*/
if ((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
{
huart->RxXferCount = 0U;
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_PEIE);
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* Disable the DMA transfer for the receiver request by setting the DMAR bit
in the UART CR3 register */
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/* At end of Rx process, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
/* If Reception till IDLE event has been selected, Disable IDLE Interrupt */
if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
{
ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
}
}
/* Initialize type of RxEvent that correspond to RxEvent callback execution;
In this case, Rx Event type is Transfer Complete */
huart->RxEventType = HAL_UART_RXEVENT_TC;
/* Check current reception Mode :
If Reception till IDLE event has been selected : use Rx Event callback */
if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
{
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Rx Event callback*/
huart->RxEventCallback(huart, huart->RxXferSize);
#else
/*Call legacy weak Rx Event callback*/
HAL_UARTEx_RxEventCallback(huart, huart->RxXferSize);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
else
{
/* In other cases : use Rx Complete callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Rx complete callback*/
huart->RxCpltCallback(huart);
#else
/*Call legacy weak Rx complete callback*/
HAL_UART_RxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
}
/**
* @brief DMA UART receive process half complete callback
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void UART_DMARxHalfCplt(DMA_HandleTypeDef *hdma)
{
UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* Initialize type of RxEvent that correspond to RxEvent callback execution;
In this case, Rx Event type is Half Transfer */
huart->RxEventType = HAL_UART_RXEVENT_HT;
/* Check current reception Mode :
If Reception till IDLE event has been selected : use Rx Event callback */
if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
{
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Rx Event callback*/
huart->RxEventCallback(huart, huart->RxXferSize / 2U);
#else
/*Call legacy weak Rx Event callback*/
HAL_UARTEx_RxEventCallback(huart, huart->RxXferSize / 2U);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
else
{
/* In other cases : use Rx Half Complete callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Rx Half complete callback*/
huart->RxHalfCpltCallback(huart);
#else
/*Call legacy weak Rx Half complete callback*/
HAL_UART_RxHalfCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
}
/**
* @brief DMA UART communication error callback.
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void UART_DMAError(DMA_HandleTypeDef *hdma)
{
uint32_t dmarequest = 0x00U;
UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
/* Stop UART DMA Tx request if ongoing */
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAT);
if ((huart->gState == HAL_UART_STATE_BUSY_TX) && dmarequest)
{
huart->TxXferCount = 0x00U;
UART_EndTxTransfer(huart);
}
/* Stop UART DMA Rx request if ongoing */
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
if ((huart->RxState == HAL_UART_STATE_BUSY_RX) && dmarequest)
{
huart->RxXferCount = 0x00U;
UART_EndRxTransfer(huart);
}
huart->ErrorCode |= HAL_UART_ERROR_DMA;
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered error callback*/
huart->ErrorCallback(huart);
#else
/*Call legacy weak error callback*/
HAL_UART_ErrorCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
/**
* @brief This function handles UART Communication Timeout. It waits
* until a flag is no longer in the specified status.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param Flag specifies the UART flag to check.
* @param Status The actual Flag status (SET or RESET).
* @param Tickstart Tick start value
* @param Timeout Timeout duration
* @retval HAL status
*/
static HAL_StatusTypeDef UART_WaitOnFlagUntilTimeout(UART_HandleTypeDef *huart, uint32_t Flag, FlagStatus Status,
uint32_t Tickstart, uint32_t Timeout)
{
/* Wait until flag is set */
while ((__HAL_UART_GET_FLAG(huart, Flag) ? SET : RESET) == Status)
{
/* Check for the Timeout */
if (Timeout != HAL_MAX_DELAY)
{
if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U))
{
return HAL_TIMEOUT;
}
if ((READ_BIT(huart->Instance->CR1, USART_CR1_RE) != 0U) && (Flag != UART_FLAG_TXE) && (Flag != UART_FLAG_TC))
{
if (__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE) == SET)
{
/* Clear Overrun Error flag*/
__HAL_UART_CLEAR_OREFLAG(huart);
/* Blocking error : transfer is aborted
Set the UART state ready to be able to start again the process,
Disable Rx Interrupts if ongoing */
UART_EndRxTransfer(huart);
huart->ErrorCode = HAL_UART_ERROR_ORE;
/* Process Unlocked */
__HAL_UNLOCK(huart);
return HAL_ERROR;
}
}
}
}
return HAL_OK;
}
/**
* @brief Start Receive operation in interrupt mode.
* @note This function could be called by all HAL UART API providing reception in Interrupt mode.
* @note When calling this function, parameters validity is considered as already checked,
* i.e. Rx State, buffer address, ...
* UART Handle is assumed as Locked.
* @param huart UART handle.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @retval HAL status
*/
HAL_StatusTypeDef UART_Start_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->RxXferCount = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
if (huart->Init.Parity != UART_PARITY_NONE)
{
/* Enable the UART Parity Error Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_PE);
}
/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
__HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
/* Enable the UART Data Register not empty Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
return HAL_OK;
}
/**
* @brief Start Receive operation in DMA mode.
* @note This function could be called by all HAL UART API providing reception in DMA mode.
* @note When calling this function, parameters validity is considered as already checked,
* i.e. Rx State, buffer address, ...
* UART Handle is assumed as Locked.
* @param huart UART handle.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @retval HAL status
*/
HAL_StatusTypeDef UART_Start_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
uint32_t *tmp;
huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->RxState = HAL_UART_STATE_BUSY_RX;
/* Set the UART DMA transfer complete callback */
huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt;
/* Set the UART DMA Half transfer complete callback */
huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt;
/* Set the DMA error callback */
huart->hdmarx->XferErrorCallback = UART_DMAError;
/* Set the DMA abort callback */
huart->hdmarx->XferAbortCallback = NULL;
/* Enable the DMA stream */
tmp = (uint32_t *)&pData;
HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t *)tmp, Size);
/* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer */
__HAL_UART_CLEAR_OREFLAG(huart);
if (huart->Init.Parity != UART_PARITY_NONE)
{
/* Enable the UART Parity Error Interrupt */
ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);
}
/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
ATOMIC_SET_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* Enable the DMA transfer for the receiver request by setting the DMAR bit
in the UART CR3 register */
ATOMIC_SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);
return HAL_OK;
}
/**
* @brief End ongoing Tx transfer on UART peripheral (following error detection or Transmit completion).
* @param huart UART handle.
* @retval None
*/
static void UART_EndTxTransfer(UART_HandleTypeDef *huart)
{
/* Disable TXEIE and TCIE interrupts */
ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE));
/* At end of Tx process, restore huart->gState to Ready */
huart->gState = HAL_UART_STATE_READY;
}
/**
* @brief End ongoing Rx transfer on UART peripheral (following error detection or Reception completion).
* @param huart UART handle.
* @retval None
*/
static void UART_EndRxTransfer(UART_HandleTypeDef *huart)
{
/* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
/* In case of reception waiting for IDLE event, disable also the IDLE IE interrupt source */
if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
{
ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
}
/* At end of Rx process, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
}
/**
* @brief DMA UART communication abort callback, when initiated by HAL services on Error
* (To be called at end of DMA Abort procedure following error occurrence).
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void UART_DMAAbortOnError(DMA_HandleTypeDef *hdma)
{
UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
huart->RxXferCount = 0x00U;
huart->TxXferCount = 0x00U;
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered error callback*/
huart->ErrorCallback(huart);
#else
/*Call legacy weak error callback*/
HAL_UART_ErrorCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
/**
* @brief DMA UART Tx communication abort callback, when initiated by user
* (To be called at end of DMA Tx Abort procedure following user abort request).
* @note When this callback is executed, User Abort complete call back is called only if no
* Abort still ongoing for Rx DMA Handle.
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void UART_DMATxAbortCallback(DMA_HandleTypeDef *hdma)
{
UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
huart->hdmatx->XferAbortCallback = NULL;
/* Check if an Abort process is still ongoing */
if (huart->hdmarx != NULL)
{
if (huart->hdmarx->XferAbortCallback != NULL)
{
return;
}
}
/* No Abort process still ongoing : All DMA channels are aborted, call user Abort Complete callback */
huart->TxXferCount = 0x00U;
huart->RxXferCount = 0x00U;
/* Reset ErrorCode */
huart->ErrorCode = HAL_UART_ERROR_NONE;
/* Restore huart->gState and huart->RxState to Ready */
huart->gState = HAL_UART_STATE_READY;
huart->RxState = HAL_UART_STATE_READY;
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
/* Call user Abort complete callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/* Call registered Abort complete callback */
huart->AbortCpltCallback(huart);
#else
/* Call legacy weak Abort complete callback */
HAL_UART_AbortCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
/**
* @brief DMA UART Rx communication abort callback, when initiated by user
* (To be called at end of DMA Rx Abort procedure following user abort request).
* @note When this callback is executed, User Abort complete call back is called only if no
* Abort still ongoing for Tx DMA Handle.
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void UART_DMARxAbortCallback(DMA_HandleTypeDef *hdma)
{
UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
huart->hdmarx->XferAbortCallback = NULL;
/* Check if an Abort process is still ongoing */
if (huart->hdmatx != NULL)
{
if (huart->hdmatx->XferAbortCallback != NULL)
{
return;
}
}
/* No Abort process still ongoing : All DMA channels are aborted, call user Abort Complete callback */
huart->TxXferCount = 0x00U;
huart->RxXferCount = 0x00U;
/* Reset ErrorCode */
huart->ErrorCode = HAL_UART_ERROR_NONE;
/* Restore huart->gState and huart->RxState to Ready */
huart->gState = HAL_UART_STATE_READY;
huart->RxState = HAL_UART_STATE_READY;
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
/* Call user Abort complete callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/* Call registered Abort complete callback */
huart->AbortCpltCallback(huart);
#else
/* Call legacy weak Abort complete callback */
HAL_UART_AbortCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
/**
* @brief DMA UART Tx communication abort callback, when initiated by user by a call to
* HAL_UART_AbortTransmit_IT API (Abort only Tx transfer)
* (This callback is executed at end of DMA Tx Abort procedure following user abort request,
* and leads to user Tx Abort Complete callback execution).
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void UART_DMATxOnlyAbortCallback(DMA_HandleTypeDef *hdma)
{
UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
huart->TxXferCount = 0x00U;
/* Restore huart->gState to Ready */
huart->gState = HAL_UART_STATE_READY;
/* Call user Abort complete callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/* Call registered Abort Transmit Complete Callback */
huart->AbortTransmitCpltCallback(huart);
#else
/* Call legacy weak Abort Transmit Complete Callback */
HAL_UART_AbortTransmitCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
/**
* @brief DMA UART Rx communication abort callback, when initiated by user by a call to
* HAL_UART_AbortReceive_IT API (Abort only Rx transfer)
* (This callback is executed at end of DMA Rx Abort procedure following user abort request,
* and leads to user Rx Abort Complete callback execution).
* @param hdma Pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA module.
* @retval None
*/
static void UART_DMARxOnlyAbortCallback(DMA_HandleTypeDef *hdma)
{
UART_HandleTypeDef *huart = (UART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
huart->RxXferCount = 0x00U;
/* Restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
/* Call user Abort complete callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/* Call registered Abort Receive Complete Callback */
huart->AbortReceiveCpltCallback(huart);
#else
/* Call legacy weak Abort Receive Complete Callback */
HAL_UART_AbortReceiveCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
/**
* @brief Sends an amount of data in non blocking mode.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
static HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart)
{
const uint16_t *tmp;
/* Check that a Tx process is ongoing */
if (huart->gState == HAL_UART_STATE_BUSY_TX)
{
if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
{
tmp = (const uint16_t *) huart->pTxBuffPtr;
huart->Instance->DR = (uint16_t)(*tmp & (uint16_t)0x01FF);
huart->pTxBuffPtr += 2U;
}
else
{
huart->Instance->DR = (uint8_t)(*huart->pTxBuffPtr++ & (uint8_t)0x00FF);
}
if (--huart->TxXferCount == 0U)
{
/* Disable the UART Transmit Data Register Empty Interrupt */
__HAL_UART_DISABLE_IT(huart, UART_IT_TXE);
/* Enable the UART Transmit Complete Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_TC);
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Wraps up transmission in non blocking mode.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
static HAL_StatusTypeDef UART_EndTransmit_IT(UART_HandleTypeDef *huart)
{
/* Disable the UART Transmit Complete Interrupt */
__HAL_UART_DISABLE_IT(huart, UART_IT_TC);
/* Tx process is ended, restore huart->gState to Ready */
huart->gState = HAL_UART_STATE_READY;
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Tx complete callback*/
huart->TxCpltCallback(huart);
#else
/*Call legacy weak Tx complete callback*/
HAL_UART_TxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
return HAL_OK;
}
/**
* @brief Receives an amount of data in non blocking mode
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{
uint8_t *pdata8bits;
uint16_t *pdata16bits;
/* Check that a Rx process is ongoing */
if (huart->RxState == HAL_UART_STATE_BUSY_RX)
{
if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
{
pdata8bits = NULL;
pdata16bits = (uint16_t *) huart->pRxBuffPtr;
*pdata16bits = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
huart->pRxBuffPtr += 2U;
}
else
{
pdata8bits = (uint8_t *) huart->pRxBuffPtr;
pdata16bits = NULL;
if ((huart->Init.WordLength == UART_WORDLENGTH_9B) || ((huart->Init.WordLength == UART_WORDLENGTH_8B) && (huart->Init.Parity == UART_PARITY_NONE)))
{
*pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
}
else
{
*pdata8bits = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
}
huart->pRxBuffPtr += 1U;
}
if (--huart->RxXferCount == 0U)
{
/* Disable the UART Data Register not empty Interrupt */
__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);
/* Disable the UART Parity Error Interrupt */
__HAL_UART_DISABLE_IT(huart, UART_IT_PE);
/* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
__HAL_UART_DISABLE_IT(huart, UART_IT_ERR);
/* Rx process is completed, restore huart->RxState to Ready */
huart->RxState = HAL_UART_STATE_READY;
/* Initialize type of RxEvent to Transfer Complete */
huart->RxEventType = HAL_UART_RXEVENT_TC;
/* Check current reception Mode :
If Reception till IDLE event has been selected : */
if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
{
/* Set reception type to Standard */
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
/* Disable IDLE interrupt */
ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
/* Check if IDLE flag is set */
if (__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE))
{
/* Clear IDLE flag in ISR */
__HAL_UART_CLEAR_IDLEFLAG(huart);
}
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Rx Event callback*/
huart->RxEventCallback(huart, huart->RxXferSize);
#else
/*Call legacy weak Rx Event callback*/
HAL_UARTEx_RxEventCallback(huart, huart->RxXferSize);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
else
{
/* Standard reception API called */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/*Call registered Rx complete callback*/
huart->RxCpltCallback(huart);
#else
/*Call legacy weak Rx complete callback*/
HAL_UART_RxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
}
return HAL_OK;
}
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
/**
* @brief Configures the UART peripheral.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval None
*/
static void UART_SetConfig(UART_HandleTypeDef *huart)
{
uint32_t tmpreg;
uint32_t pclk;
/* Check the parameters */
assert_param(IS_UART_BAUDRATE(huart->Init.BaudRate));
assert_param(IS_UART_STOPBITS(huart->Init.StopBits));
assert_param(IS_UART_PARITY(huart->Init.Parity));
assert_param(IS_UART_MODE(huart->Init.Mode));
/*-------------------------- USART CR2 Configuration -----------------------*/
/* Configure the UART Stop Bits: Set STOP[13:12] bits
according to huart->Init.StopBits value */
MODIFY_REG(huart->Instance->CR2, USART_CR2_STOP, huart->Init.StopBits);
/*-------------------------- USART CR1 Configuration -----------------------*/
/* Configure the UART Word Length, Parity and mode:
Set the M bits according to huart->Init.WordLength value
Set PCE and PS bits according to huart->Init.Parity value
Set TE and RE bits according to huart->Init.Mode value
Set OVER8 bit according to huart->Init.OverSampling value */
#if defined(USART_CR1_OVER8)
tmpreg = (uint32_t)huart->Init.WordLength | huart->Init.Parity | huart->Init.Mode | huart->Init.OverSampling;
MODIFY_REG(huart->Instance->CR1,
(uint32_t)(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | USART_CR1_TE | USART_CR1_RE | USART_CR1_OVER8),
tmpreg);
#else
tmpreg = (uint32_t)huart->Init.WordLength | huart->Init.Parity | huart->Init.Mode;
MODIFY_REG(huart->Instance->CR1,
(uint32_t)(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | USART_CR1_TE | USART_CR1_RE),
tmpreg);
#endif /* USART_CR1_OVER8 */
/*-------------------------- USART CR3 Configuration -----------------------*/
/* Configure the UART HFC: Set CTSE and RTSE bits according to huart->Init.HwFlowCtl value */
MODIFY_REG(huart->Instance->CR3, (USART_CR3_RTSE | USART_CR3_CTSE), huart->Init.HwFlowCtl);
if(huart->Instance == USART1)
{
pclk = HAL_RCC_GetPCLK2Freq();
}
else
{
pclk = HAL_RCC_GetPCLK1Freq();
}
/*-------------------------- USART BRR Configuration ---------------------*/
#if defined(USART_CR1_OVER8)
if (huart->Init.OverSampling == UART_OVERSAMPLING_8)
{
huart->Instance->BRR = UART_BRR_SAMPLING8(pclk, huart->Init.BaudRate);
}
else
{
huart->Instance->BRR = UART_BRR_SAMPLING16(pclk, huart->Init.BaudRate);
}
#else
huart->Instance->BRR = UART_BRR_SAMPLING16(pclk, huart->Init.BaudRate);
#endif /* USART_CR1_OVER8 */
}
/**
* @}
*/
#endif /* HAL_UART_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/